2006-12-31 18:02:22 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
iseq.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: 2006-07-11(Tue) 09:00:03 +0900
|
|
|
|
|
|
|
|
Copyright (C) 2006 Koichi Sasada
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
* internal.h: declare internal functions here.
* node.h: declare NODE dependent internal functions here.
* iseq.h: declare rb_iseq_t dependent internal functions here.
* vm_core.h: declare rb_thread_t dependent internal functions here.
* bignum.c, class.c, compile.c, complex.c, cont.c, dir.c, encoding.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c, io.c,
iseq.c, load.c, marshal.c, math.c, numeric.c, object.c, parse.y,
proc.c, process.c, range.c, rational.c, re.c, ruby.c, string.c,
thread.c, time.c, transcode.c, variable.c, vm.c,
tool/compile_prelude.rb: don't declare internal functions declared
in above headers. include above headers if required.
Note that rb_thread_mark() was declared as
void rb_thread_mark(rb_thread_t *th) in cont.c but defined as
void rb_thread_mark(void *ptr) in vm.c. Now it is declared as
the later in internal.h.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32156 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2011-06-18 02:43:38 +04:00
|
|
|
#include "internal.h"
|
2014-11-15 14:49:06 +03:00
|
|
|
#include "ruby/util.h"
|
* iseq.c, vm_eval.c: set th->base_block properly.
th->base_block is information for (a) parsing, (b) compiling
and (c) setting up the frame to execute the program passed by
`eval' method. For example, (1) parser need to know up-level
variables to detect it is variable or method without paren.
Befor (a), (b) and (c), VM set th->base_block by passed bindng
(or previous frame information). After execute (a), (b) and (c),
VM should clear th->base_block. However, if (a), (b) or (c)
raises an exception, then th->base_block is not cleared.
Problem is that the uncleared value th->balo_block is used for
irrelevant iseq compilation. It causes SEGV or critical error.
I tried to solve this problem: to clear them before exception,
but finally I found out that it is difficult to do it (Ruby
program can be run in many places).
Because of this background, I set th->base_block before
compiling iseq and restore it after compiling.
Basically, th->base_block is dirty hack (similar to global
variable) and this patch is also dirty.
* bootstraptest/test_eval.rb: add a test for above.
* internal.h: remove unused decl.
* iseq.c (rb_iseq_compile_with_option): add base_block parameter.
set th->base_block before compation and restore it after
compilation.
* ruby.c (require_libraries): pass 0 as base_block instead of
setting th->base_block
* tool/compile_prelude.rb (prelude_eval): apply above changes.
* vm.c, vm_eval.c: ditto.
* vm_core.h: add comments.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36179 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-22 13:32:56 +04:00
|
|
|
#include "eval_intern.h"
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2014-12-16 04:14:27 +03:00
|
|
|
#ifdef HAVE_DLADDR
|
|
|
|
# include <dlfcn.h>
|
|
|
|
#endif
|
|
|
|
|
2018-01-04 04:46:01 +03:00
|
|
|
#define RUBY_VM_INSNS_INFO 1
|
2009-10-16 08:40:11 +04:00
|
|
|
/* #define RUBY_MARK_FREE_DEBUG 1 */
|
* 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 "gc.h"
|
|
|
|
#include "vm_core.h"
|
* include/ruby/node.h, vm_core.h: move definition of
RUBY_VM_METHOD_NODE to node.h.
* class.c, common.mk: remove useless inclusion.
* compile.h, iseq.h, vm_core.h: rename compile.h to iseq.h.
move some definitions from vm_core.h to iseq.h.
* compile.c, iseq.c, vm.c: ditto.
* eval.c, compile.c: move some functions for parser
from eval.c to compile.c.
* eval_intern.h, vm_core.h: move va_init_list() macro to
vm_core.h.
* iseq.c (rb_iseq_new_top, rb_iseq_first_lineno): added.
* load.c, ruby.c: use rb_iseq_new_top() instead of
rb_iseq_new() with ISEQ_TYPE_TOP constant directly.
* proc.c: use rb_iseq_first_lineno() instead of accessing
iseq structure.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19472 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 11:49:45 +04:00
|
|
|
#include "iseq.h"
|
2016-05-14 21:43:11 +03:00
|
|
|
#include "id_table.h"
|
* 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
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
#include "insns.inc"
|
|
|
|
#include "insns_info.inc"
|
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
|
|
|
#include "mjit.h"
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-01-17 11:48:52 +03:00
|
|
|
VALUE rb_cISeq;
|
2015-12-07 20:23:18 +03:00
|
|
|
static VALUE iseqw_new(const rb_iseq_t *iseq);
|
|
|
|
static const rb_iseq_t *iseqw_check(VALUE iseqw);
|
2007-01-17 11:48:52 +03:00
|
|
|
|
2018-01-09 17:05:23 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2
|
|
|
|
static struct succ_index_table *succ_index_table_create(int max_pos, int *data, int size);
|
|
|
|
static unsigned int *succ_index_table_invert(int max_pos, struct succ_index_table *sd, int size);
|
|
|
|
static int succ_index_lookup(const struct succ_index_table *sd, int x);
|
|
|
|
#endif
|
|
|
|
|
2009-02-12 13:42:36 +03:00
|
|
|
#define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
|
|
|
|
|
2009-02-18 08:33:36 +03:00
|
|
|
static inline VALUE
|
|
|
|
obj_resurrect(VALUE obj)
|
|
|
|
{
|
|
|
|
if (hidden_obj_p(obj)) {
|
|
|
|
switch (BUILTIN_TYPE(obj)) {
|
|
|
|
case T_STRING:
|
|
|
|
obj = rb_str_resurrect(obj);
|
|
|
|
break;
|
|
|
|
case T_ARRAY:
|
|
|
|
obj = rb_ary_resurrect(obj);
|
|
|
|
break;
|
2018-12-21 02:21:50 +03:00
|
|
|
case T_HASH:
|
|
|
|
obj = rb_hash_resurrect(obj);
|
|
|
|
break;
|
2009-02-18 08:33:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static void
|
|
|
|
compile_data_free(struct iseq_compile_data *compile_data)
|
|
|
|
{
|
|
|
|
if (compile_data) {
|
|
|
|
struct iseq_compile_data_storage *cur, *next;
|
|
|
|
cur = compile_data->storage_head;
|
|
|
|
while (cur) {
|
|
|
|
next = cur->next;
|
|
|
|
ruby_xfree(cur);
|
|
|
|
cur = next;
|
|
|
|
}
|
2016-05-14 21:43:11 +03:00
|
|
|
if (compile_data->ivar_cache_table) {
|
|
|
|
rb_id_table_free(compile_data->ivar_cache_table);
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
ruby_xfree(compile_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
void
|
|
|
|
rb_iseq_free(const rb_iseq_t *iseq)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2007-06-25 06:44:20 +04:00
|
|
|
RUBY_FREE_ENTER("iseq");
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-05-12 04:24:16 +03:00
|
|
|
if (iseq && iseq->body) {
|
2018-05-12 04:24:18 +03:00
|
|
|
struct rb_iseq_constant_body *const body = iseq->body;
|
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
|
|
|
mjit_free_iseq(iseq); /* Notify MJIT */
|
2018-05-12 04:24:18 +03:00
|
|
|
ruby_xfree((void *)body->iseq_encoded);
|
|
|
|
ruby_xfree((void *)body->insns_info.body);
|
|
|
|
if (body->insns_info.positions) ruby_xfree((void *)body->insns_info.positions);
|
2018-01-09 17:05:23 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
|
2018-01-09 17:05:23 +03:00
|
|
|
#endif
|
2019-04-11 13:36:36 +03:00
|
|
|
if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl))
|
|
|
|
ruby_xfree((void *)body->local_table);
|
2018-05-12 04:24:18 +03:00
|
|
|
ruby_xfree((void *)body->is_entries);
|
2018-05-12 04:24:16 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->ci_entries) {
|
2018-05-12 04:24:16 +03:00
|
|
|
unsigned int i;
|
2018-05-12 04:24:18 +03:00
|
|
|
struct rb_call_info_with_kwarg *ci_kw_entries = (struct rb_call_info_with_kwarg *)&body->ci_entries[body->ci_size];
|
|
|
|
for (i=0; i<body->ci_kw_size; i++) {
|
2018-05-12 04:24:16 +03:00
|
|
|
const struct rb_call_info_kw_arg *kw_arg = ci_kw_entries[i].kw_arg;
|
|
|
|
ruby_xfree((void *)kw_arg);
|
2014-11-03 08:43:31 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
ruby_xfree(body->ci_entries);
|
|
|
|
ruby_xfree(body->cc_entries);
|
2018-05-12 04:24:16 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
ruby_xfree((void *)body->catch_table);
|
|
|
|
ruby_xfree((void *)body->param.opt_table);
|
2015-07-23 12:34:31 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->param.keyword != NULL) {
|
|
|
|
ruby_xfree((void *)body->param.keyword->default_values);
|
|
|
|
ruby_xfree((void *)body->param.keyword);
|
2015-07-07 05:41:52 +03:00
|
|
|
}
|
2018-05-12 04:24:16 +03:00
|
|
|
compile_data_free(ISEQ_COMPILE_DATA(iseq));
|
2018-05-12 04:24:18 +03:00
|
|
|
ruby_xfree(body);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2018-11-26 21:16:39 +03:00
|
|
|
|
2018-12-23 03:45:11 +03:00
|
|
|
if (iseq && ISEQ_EXECUTABLE_P(iseq) && iseq->aux.exec.local_hooks) {
|
2018-12-06 13:52:27 +03:00
|
|
|
rb_hook_list_free(iseq->aux.exec.local_hooks);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
RUBY_FREE_LEAVE("iseq");
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2018-03-19 21:21:54 +03:00
|
|
|
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
|
|
|
|
static VALUE
|
|
|
|
rb_vm_insn_addr2insn2(const void *addr)
|
|
|
|
{
|
2018-06-06 23:57:48 +03:00
|
|
|
return (VALUE)rb_vm_insn_addr2insn(addr);
|
2018-03-19 21:21:54 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_vm_insn_null_translator(const void *addr)
|
|
|
|
{
|
|
|
|
return (VALUE)addr;
|
|
|
|
}
|
|
|
|
|
2019-04-20 04:19:47 +03:00
|
|
|
typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
|
2018-03-19 21:21:54 +03:00
|
|
|
typedef VALUE rb_vm_insns_translator_t(const void *addr);
|
|
|
|
|
|
|
|
static int
|
2019-04-20 04:19:47 +03:00
|
|
|
iseq_extract_values(VALUE *code, size_t pos, iseq_value_itr_t * func, void *data, rb_vm_insns_translator_t * translator)
|
2018-03-19 21:21:54 +03:00
|
|
|
{
|
|
|
|
VALUE insn = translator((void *)code[pos]);
|
|
|
|
int len = insn_len(insn);
|
|
|
|
int op_no;
|
|
|
|
const char *types = insn_op_types(insn);
|
|
|
|
|
|
|
|
for (op_no = 0; types[op_no]; op_no++) {
|
|
|
|
char type = types[op_no];
|
|
|
|
switch (type) {
|
|
|
|
case TS_CDHASH:
|
|
|
|
case TS_ISEQ:
|
|
|
|
case TS_VALUE:
|
|
|
|
{
|
|
|
|
VALUE op = code[pos + op_no + 1];
|
|
|
|
if (!SPECIAL_CONST_P(op)) {
|
2019-04-20 04:19:47 +03:00
|
|
|
VALUE newop = func(data, op);
|
|
|
|
if (newop != op) {
|
|
|
|
code[pos + op_no + 1] = newop;
|
|
|
|
}
|
2018-03-19 21:21:54 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TS_ISE:
|
|
|
|
{
|
|
|
|
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)code[pos + op_no + 1];
|
|
|
|
if (is->once.value) {
|
2019-04-20 04:19:47 +03:00
|
|
|
VALUE nv = func(data, is->once.value);
|
|
|
|
if (is->once.value != nv) {
|
|
|
|
is->once.value = nv;
|
|
|
|
}
|
2018-03-19 21:21:54 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
|
|
|
|
{
|
|
|
|
unsigned int size;
|
2019-04-20 04:19:47 +03:00
|
|
|
VALUE *code;
|
2018-03-19 21:21:54 +03:00
|
|
|
size_t n;
|
|
|
|
rb_vm_insns_translator_t * translator;
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2018-03-19 21:21:54 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
size = body->iseq_size;
|
|
|
|
code = body->iseq_encoded;
|
2018-03-19 21:21:54 +03:00
|
|
|
|
|
|
|
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
|
|
|
|
if (FL_TEST(iseq, ISEQ_TRANSLATED)) {
|
|
|
|
translator = rb_vm_insn_addr2insn2;
|
2019-01-09 16:58:49 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-03-19 21:21:54 +03:00
|
|
|
translator = rb_vm_insn_null_translator;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
translator = rb_vm_insn_null_translator;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (n = 0; n < size;) {
|
|
|
|
n += iseq_extract_values(code, n, func, data, translator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-20 04:19:47 +03:00
|
|
|
static VALUE
|
|
|
|
update_each_insn_value(void *ctx, VALUE obj)
|
|
|
|
{
|
2019-05-18 12:23:47 +03:00
|
|
|
return rb_gc_location(obj);
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_iseq_update_references(rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
if (iseq->body) {
|
|
|
|
struct rb_iseq_constant_body *body = iseq->body;
|
|
|
|
|
2019-05-18 12:23:47 +03:00
|
|
|
body->variable.coverage = rb_gc_location(body->variable.coverage);
|
|
|
|
body->variable.pc2branchindex = rb_gc_location(body->variable.pc2branchindex);
|
|
|
|
body->location.label = rb_gc_location(body->location.label);
|
|
|
|
body->location.base_label = rb_gc_location(body->location.base_label);
|
|
|
|
body->location.pathobj = rb_gc_location(body->location.pathobj);
|
2019-04-20 04:19:47 +03:00
|
|
|
if (body->local_iseq) {
|
2019-05-18 12:23:47 +03:00
|
|
|
body->local_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->local_iseq);
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
if (body->parent_iseq) {
|
2019-05-18 12:23:47 +03:00
|
|
|
body->parent_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->parent_iseq);
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
if (FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) {
|
|
|
|
rb_iseq_each_value(iseq, update_each_insn_value, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
i = body->param.keyword->required_num;
|
|
|
|
|
|
|
|
for (j = 0; i < body->param.keyword->num; i++, j++) {
|
|
|
|
VALUE obj = body->param.keyword->default_values[j];
|
|
|
|
if (obj != Qundef) {
|
2019-05-18 12:23:47 +03:00
|
|
|
body->param.keyword->default_values[j] = rb_gc_location(obj);
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (body->catch_table) {
|
|
|
|
struct iseq_catch_table *table = body->catch_table;
|
|
|
|
unsigned int i;
|
|
|
|
for(i = 0; i < table->size; i++) {
|
|
|
|
struct iseq_catch_table_entry *entry;
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
|
2019-04-20 04:19:47 +03:00
|
|
|
if (entry->iseq) {
|
2019-05-18 12:23:47 +03:00
|
|
|
entry->iseq = (rb_iseq_t *)rb_gc_location((VALUE)entry->iseq);
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-20 05:40:41 +03:00
|
|
|
#if USE_MJIT
|
|
|
|
mjit_update_references(iseq);
|
|
|
|
#endif
|
2019-04-20 04:19:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2018-03-19 21:21:54 +03:00
|
|
|
each_insn_value(void *ctx, VALUE obj)
|
|
|
|
{
|
2019-04-20 04:19:47 +03:00
|
|
|
rb_gc_mark_no_pin(obj);
|
|
|
|
return obj;
|
2018-03-19 21:21:54 +03:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
void
|
|
|
|
rb_iseq_mark(const rb_iseq_t *iseq)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-15 11:29:22 +03:00
|
|
|
RUBY_MARK_ENTER("iseq");
|
2009-07-13 13:30:23 +04:00
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
RUBY_MARK_UNLESS_NULL(iseq->wrapper);
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
if (iseq->body) {
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2012-05-22 12:31:38 +04:00
|
|
|
|
2018-03-20 11:36:42 +03:00
|
|
|
if (FL_TEST(iseq, ISEQ_MARKABLE_ISEQ)) {
|
2018-03-19 21:21:54 +03:00
|
|
|
rb_iseq_each_value(iseq, each_insn_value, NULL);
|
|
|
|
}
|
|
|
|
|
2019-04-20 04:19:47 +03:00
|
|
|
rb_gc_mark_no_pin(body->variable.coverage);
|
|
|
|
rb_gc_mark_no_pin(body->variable.pc2branchindex);
|
|
|
|
rb_gc_mark_no_pin(body->location.label);
|
|
|
|
rb_gc_mark_no_pin(body->location.base_label);
|
|
|
|
rb_gc_mark_no_pin(body->location.pathobj);
|
|
|
|
RUBY_MARK_NO_PIN_UNLESS_NULL((VALUE)body->parent_iseq);
|
2018-03-19 21:21:54 +03:00
|
|
|
|
|
|
|
if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
|
2018-05-16 04:40:44 +03:00
|
|
|
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
|
2018-03-19 21:21:54 +03:00
|
|
|
int i, j;
|
|
|
|
|
2018-05-16 04:40:44 +03:00
|
|
|
i = keyword->required_num;
|
2018-03-19 21:21:54 +03:00
|
|
|
|
2018-05-16 04:40:44 +03:00
|
|
|
for (j = 0; i < keyword->num; i++, j++) {
|
|
|
|
VALUE obj = keyword->default_values[j];
|
2018-04-14 00:36:51 +03:00
|
|
|
if (!SPECIAL_CONST_P(obj)) {
|
2018-03-19 21:21:54 +03:00
|
|
|
rb_gc_mark(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (body->catch_table) {
|
|
|
|
const struct iseq_catch_table *table = body->catch_table;
|
|
|
|
unsigned int i;
|
|
|
|
for(i = 0; i < table->size; i++) {
|
|
|
|
const struct iseq_catch_table_entry *entry;
|
2019-05-31 09:58:50 +03:00
|
|
|
entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
|
2018-03-19 21:21:54 +03:00
|
|
|
if (entry->iseq) {
|
2019-04-20 04:19:47 +03:00
|
|
|
rb_gc_mark_no_pin((VALUE)entry->iseq);
|
2018-03-19 21:21:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-22 13:55:02 +03:00
|
|
|
}
|
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
if (FL_TEST_RAW(iseq, ISEQ_NOT_LOADED_YET)) {
|
2015-12-08 16:58:50 +03:00
|
|
|
rb_gc_mark(iseq->aux.loader.obj);
|
|
|
|
}
|
2018-12-06 13:52:27 +03:00
|
|
|
else if (FL_TEST_RAW(iseq, ISEQ_USE_COMPILE_DATA)) {
|
2015-12-02 10:52:12 +03:00
|
|
|
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
|
2019-04-20 04:19:47 +03:00
|
|
|
if (RTEST(compile_data->mark_ary)) {
|
|
|
|
rb_gc_mark(compile_data->mark_ary);
|
|
|
|
}
|
2019-04-17 12:41:41 +03:00
|
|
|
RUBY_MARK_UNLESS_NULL(compile_data->err_info);
|
2019-04-20 04:19:47 +03:00
|
|
|
if (RTEST(compile_data->catch_table_ary)) {
|
|
|
|
rb_gc_mark(compile_data->catch_table_ary);
|
|
|
|
}
|
|
|
|
VM_ASSERT(compile_data != NULL);
|
2018-12-06 13:52:27 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* executable */
|
|
|
|
VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
|
|
|
|
if (iseq->aux.exec.local_hooks) {
|
|
|
|
rb_hook_list_mark(iseq->aux.exec.local_hooks);
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2015-07-15 11:29:22 +03:00
|
|
|
|
2007-06-25 06:44:20 +04:00
|
|
|
RUBY_MARK_LEAVE("iseq");
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-08-12 15:18:51 +03:00
|
|
|
static size_t
|
|
|
|
param_keyword_size(const struct rb_iseq_param_keyword *pkw)
|
|
|
|
{
|
|
|
|
size_t size = 0;
|
|
|
|
|
|
|
|
if (!pkw) return size;
|
|
|
|
|
|
|
|
size += sizeof(struct rb_iseq_param_keyword);
|
|
|
|
size += sizeof(VALUE) * (pkw->num - pkw->required_num);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2009-06-17 02:23:53 +04:00
|
|
|
static size_t
|
2015-09-03 22:48:12 +03:00
|
|
|
iseq_memsize(const rb_iseq_t *iseq)
|
2009-06-17 02:23:53 +04:00
|
|
|
{
|
2015-08-12 15:18:51 +03:00
|
|
|
size_t size = 0; /* struct already counted as RVALUE size */
|
2015-12-02 16:58:07 +03:00
|
|
|
const struct rb_iseq_constant_body *body = iseq->body;
|
2015-08-12 15:18:51 +03:00
|
|
|
const struct iseq_compile_data *compile_data;
|
2009-06-17 02:23:53 +04:00
|
|
|
|
2015-12-02 16:58:07 +03:00
|
|
|
/* TODO: should we count original_iseq? */
|
2015-08-12 15:18:51 +03:00
|
|
|
|
|
|
|
if (body) {
|
2015-09-19 20:59:58 +03:00
|
|
|
struct rb_call_info_with_kwarg *ci_kw_entries = (struct rb_call_info_with_kwarg *)&body->ci_entries[body->ci_size];
|
2015-08-12 15:18:51 +03:00
|
|
|
|
|
|
|
size += sizeof(struct rb_iseq_constant_body);
|
|
|
|
size += body->iseq_size * sizeof(VALUE);
|
2018-01-01 15:51:21 +03:00
|
|
|
size += body->insns_info.size * (sizeof(struct iseq_insn_info_entry) + sizeof(unsigned int));
|
2015-08-12 15:18:51 +03:00
|
|
|
size += body->local_table_size * sizeof(ID);
|
|
|
|
if (body->catch_table) {
|
|
|
|
size += iseq_catch_table_bytes(body->catch_table->size);
|
2015-07-07 05:41:52 +03:00
|
|
|
}
|
2015-08-12 15:18:51 +03:00
|
|
|
size += (body->param.opt_num + 1) * sizeof(VALUE);
|
|
|
|
size += param_keyword_size(body->param.keyword);
|
2015-11-01 05:13:54 +03:00
|
|
|
|
|
|
|
/* body->is_entries */
|
2015-08-12 15:18:51 +03:00
|
|
|
size += body->is_size * sizeof(union iseq_inline_storage_entry);
|
2015-11-01 05:13:54 +03:00
|
|
|
|
|
|
|
/* body->ci_entries */
|
2015-09-19 20:59:58 +03:00
|
|
|
size += body->ci_size * sizeof(struct rb_call_info);
|
|
|
|
size += body->ci_kw_size * sizeof(struct rb_call_info_with_kwarg);
|
2015-08-12 15:18:51 +03:00
|
|
|
|
2015-11-01 05:13:54 +03:00
|
|
|
/* body->cc_entries */
|
|
|
|
size += body->ci_size * sizeof(struct rb_call_cache);
|
|
|
|
size += body->ci_kw_size * sizeof(struct rb_call_cache);
|
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
if (ci_kw_entries) {
|
2015-08-12 15:18:51 +03:00
|
|
|
unsigned int i;
|
2015-07-07 05:41:52 +03:00
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
for (i = 0; i < body->ci_kw_size; i++) {
|
|
|
|
const struct rb_call_info_kw_arg *kw_arg = ci_kw_entries[i].kw_arg;
|
2015-07-07 05:41:52 +03:00
|
|
|
|
2015-08-12 15:18:51 +03:00
|
|
|
if (kw_arg) {
|
|
|
|
size += rb_call_info_kw_arg_bytes(kw_arg->keyword_len);
|
|
|
|
}
|
compile: translate iseq in-place
running "ruby -rpp -e 'pp GC.stat'", a reduction in
malloc usage is shown:
before:
:malloc_increase=>118784,
:oldmalloc_increase=>1178736,
after:
:malloc_increase=>99832,
:oldmalloc_increase=>1031976,
For "ruby -e exit", valgrind reports over 300K reduction in
overall allocations (and unnecessary memory copies).
before:
total heap usage: 49,622 allocs, 20,492 frees, 8,697,493 bytes allocated
after:
total heap usage: 48,935 allocs, 19,805 frees, 8,373,773 bytes allocated
(numbers from x86-64)
v2 changes based on ko1 recommendations [ruby-core:64883]:
- squashed in-place direct thread translation to avoid alloc+copy
- renamed rb_iseq_untranslate_threaded_code to rb_iseq_original_iseq,
cache new iseq->iseq_original field.
* compile.c (rb_iseq_translate_threaded_code): modify in-place w/o copy
(rb_vm_addr2insn): new function for debug
(rb_iseq_original_iseq): ditto
(iseq_set_sequence): assign iseq_encoded directly
[Feature #10185]
* vm_core (rb_iseq_t): move original ->iseq to bottom
* iseq.c (iseq_free, iseq_free): adjust for new layout
(rb_iseq_disasm): use original iseq for dump
(iseq_data_to_ary): ditto
(rb_iseq_line_trace_each): ditto
(rb_iseq_build_for_ruby2cext): use iseq_encoded directly
* vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47508 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-10 10:14:07 +04:00
|
|
|
}
|
2015-07-07 05:41:52 +03:00
|
|
|
}
|
2015-08-12 15:18:51 +03:00
|
|
|
}
|
|
|
|
|
2015-12-02 10:52:12 +03:00
|
|
|
compile_data = ISEQ_COMPILE_DATA(iseq);
|
2015-08-12 15:18:51 +03:00
|
|
|
if (compile_data) {
|
|
|
|
struct iseq_compile_data_storage *cur;
|
|
|
|
|
|
|
|
size += sizeof(struct iseq_compile_data);
|
|
|
|
|
|
|
|
cur = compile_data->storage_head;
|
|
|
|
while (cur) {
|
2018-01-14 14:19:18 +03:00
|
|
|
size += cur->size + offsetof(struct iseq_compile_data_storage, buff);
|
2015-08-12 15:18:51 +03:00
|
|
|
cur = cur->next;
|
2009-06-17 02:23:53 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
static rb_iseq_t *
|
|
|
|
iseq_alloc(void)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-12-08 16:58:50 +03:00
|
|
|
rb_iseq_t *iseq = iseq_imemo_alloc();
|
2015-07-22 13:55:02 +03:00
|
|
|
iseq->body = ZALLOC(struct rb_iseq_constant_body);
|
2015-07-22 01:52:59 +03:00
|
|
|
return iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2017-06-01 03:05:33 +03:00
|
|
|
VALUE
|
|
|
|
rb_iseq_pathobj_new(VALUE path, VALUE realpath)
|
2012-05-22 12:31:38 +04:00
|
|
|
{
|
2017-06-01 03:05:33 +03:00
|
|
|
VALUE pathobj;
|
|
|
|
VM_ASSERT(RB_TYPE_P(path, T_STRING));
|
|
|
|
VM_ASSERT(realpath == Qnil || RB_TYPE_P(realpath, T_STRING));
|
|
|
|
|
|
|
|
if (path == realpath ||
|
|
|
|
(!NIL_P(realpath) && rb_str_cmp(path, realpath) == 0)) {
|
|
|
|
pathobj = rb_fstring(path);
|
2013-06-19 10:26:01 +04:00
|
|
|
}
|
|
|
|
else {
|
2017-06-01 03:05:33 +03:00
|
|
|
if (!NIL_P(realpath)) realpath = rb_fstring(realpath);
|
|
|
|
pathobj = rb_ary_new_from_args(2, rb_fstring(path), realpath);
|
|
|
|
rb_obj_freeze(pathobj);
|
2013-06-19 10:26:01 +04:00
|
|
|
}
|
2017-06-01 03:05:33 +03:00
|
|
|
return pathobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
|
|
|
|
{
|
|
|
|
RB_OBJ_WRITE(iseq, &iseq->body->location.pathobj,
|
|
|
|
rb_iseq_pathobj_new(path, realpath));
|
|
|
|
}
|
|
|
|
|
|
|
|
static rb_iseq_location_t *
|
2018-11-05 05:13:45 +03:00
|
|
|
iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location, const int node_id)
|
2017-06-01 03:05:33 +03:00
|
|
|
{
|
|
|
|
rb_iseq_location_t *loc = &iseq->body->location;
|
|
|
|
|
|
|
|
rb_iseq_pathobj_set(iseq, path, realpath);
|
2015-07-22 01:52:59 +03:00
|
|
|
RB_OBJ_WRITE(iseq, &loc->label, name);
|
|
|
|
RB_OBJ_WRITE(iseq, &loc->base_label, name);
|
2012-06-04 06:49:37 +04:00
|
|
|
loc->first_lineno = first_lineno;
|
2018-01-09 11:45:35 +03:00
|
|
|
if (code_location) {
|
2018-11-05 05:13:45 +03:00
|
|
|
loc->node_id = node_id;
|
2018-01-09 11:45:35 +03:00
|
|
|
loc->code_location = *code_location;
|
2017-12-05 11:56:50 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-01-09 11:45:35 +03:00
|
|
|
loc->code_location.beg_pos.lineno = 0;
|
|
|
|
loc->code_location.beg_pos.column = 0;
|
|
|
|
loc->code_location.end_pos.lineno = -1;
|
|
|
|
loc->code_location.end_pos.column = -1;
|
2017-12-05 11:56:50 +03:00
|
|
|
}
|
|
|
|
|
2012-05-22 12:31:38 +04:00
|
|
|
return loc;
|
|
|
|
}
|
|
|
|
|
2007-07-04 00:12:55 +04:00
|
|
|
static void
|
2015-07-22 01:52:59 +03:00
|
|
|
set_relation(rb_iseq_t *iseq, const rb_iseq_t *piseq)
|
2007-07-04 00:12:55 +04:00
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
const VALUE type = body->type;
|
2007-07-04 00:12:55 +04:00
|
|
|
|
|
|
|
/* set class nest stack */
|
|
|
|
if (type == ISEQ_TYPE_TOP) {
|
2018-05-12 04:24:18 +03:00
|
|
|
body->local_iseq = iseq;
|
2007-07-04 00:12:55 +04:00
|
|
|
}
|
|
|
|
else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
|
2018-05-12 04:24:18 +03:00
|
|
|
body->local_iseq = iseq;
|
2007-07-04 00:12:55 +04:00
|
|
|
}
|
2015-07-22 01:52:59 +03:00
|
|
|
else if (piseq) {
|
2018-05-12 04:24:18 +03:00
|
|
|
body->local_iseq = piseq->body->local_iseq;
|
2012-11-01 16:20:00 +04:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
if (piseq) {
|
2018-05-12 04:24:18 +03:00
|
|
|
body->parent_iseq = piseq;
|
2007-07-04 00:12:55 +04:00
|
|
|
}
|
2012-12-10 10:11:16 +04:00
|
|
|
|
|
|
|
if (type == ISEQ_TYPE_MAIN) {
|
2018-05-12 04:24:18 +03:00
|
|
|
body->local_iseq = iseq;
|
2012-12-10 10:11:16 +04:00
|
|
|
}
|
2007-07-04 00:12:55 +04:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
* 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
|
|
|
prepare_iseq_build(rb_iseq_t *iseq,
|
2018-11-05 05:14:00 +03:00
|
|
|
VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_location_t *code_location, const int node_id,
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *parent, enum iseq_type type,
|
* 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
|
|
|
const rb_compile_option_t *option)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2016-03-10 08:32:49 +03:00
|
|
|
VALUE coverage = Qfalse;
|
2017-01-12 10:41:35 +03:00
|
|
|
VALUE err_info = Qnil;
|
2018-05-12 04:24:18 +03:00
|
|
|
struct rb_iseq_constant_body *const body = iseq->body;
|
2017-01-12 10:41:35 +03:00
|
|
|
|
|
|
|
if (parent && (type == ISEQ_TYPE_MAIN || type == ISEQ_TYPE_TOP))
|
|
|
|
err_info = Qfalse;
|
2016-03-10 08:32:49 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
body->type = type;
|
2012-05-22 12:31:38 +04:00
|
|
|
set_relation(iseq, parent);
|
|
|
|
|
2013-11-27 03:30:25 +04:00
|
|
|
name = rb_fstring(name);
|
2018-11-05 05:13:45 +03:00
|
|
|
iseq_location_setup(iseq, name, path, realpath, first_lineno, code_location, node_id);
|
2018-05-12 04:24:18 +03:00
|
|
|
if (iseq != body->local_iseq) {
|
|
|
|
RB_OBJ_WRITE(iseq, &body->location.base_label, body->local_iseq->body->location.label);
|
2012-05-22 12:31:38 +04:00
|
|
|
}
|
2018-03-19 21:21:54 +03:00
|
|
|
ISEQ_COVERAGE_SET(iseq, Qnil);
|
|
|
|
ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
|
2018-05-12 04:24:18 +03:00
|
|
|
body->variable.flip_count = 0;
|
2007-02-25 19:29:26 +03:00
|
|
|
|
2017-11-18 12:39:41 +03:00
|
|
|
ISEQ_COMPILE_DATA_ALLOC(iseq);
|
2017-01-12 10:41:35 +03:00
|
|
|
RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err_info);
|
2015-12-02 10:52:12 +03:00
|
|
|
RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->mark_ary, rb_ary_tmp_new(3));
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-12-02 10:52:12 +03:00
|
|
|
ISEQ_COMPILE_DATA(iseq)->storage_head = ISEQ_COMPILE_DATA(iseq)->storage_current =
|
2007-02-25 19:29:26 +03:00
|
|
|
(struct iseq_compile_data_storage *)
|
|
|
|
ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
|
2018-01-14 14:19:18 +03:00
|
|
|
offsetof(struct iseq_compile_data_storage, buff));
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2019-04-10 15:05:15 +03:00
|
|
|
RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, Qnil);
|
2015-12-02 10:52:12 +03:00
|
|
|
ISEQ_COMPILE_DATA(iseq)->storage_head->pos = 0;
|
|
|
|
ISEQ_COMPILE_DATA(iseq)->storage_head->next = 0;
|
|
|
|
ISEQ_COMPILE_DATA(iseq)->storage_head->size =
|
2007-02-25 19:29:26 +03:00
|
|
|
INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
|
2015-12-02 10:52:12 +03:00
|
|
|
ISEQ_COMPILE_DATA(iseq)->option = option;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2016-05-14 21:43:11 +03:00
|
|
|
ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = NULL;
|
2016-05-11 15:50:38 +03:00
|
|
|
|
2016-03-10 11:34:18 +03:00
|
|
|
if (option->coverage_enabled) {
|
2008-07-08 19:13:22 +04:00
|
|
|
VALUE coverages = rb_get_coverages();
|
2008-07-03 16:55:12 +04:00
|
|
|
if (RTEST(coverages)) {
|
2017-06-01 03:05:33 +03:00
|
|
|
coverage = rb_hash_lookup(coverages, rb_iseq_path(iseq));
|
2016-03-10 08:32:49 +03:00
|
|
|
if (NIL_P(coverage)) coverage = Qfalse;
|
2008-07-01 20:55:30 +04:00
|
|
|
}
|
|
|
|
}
|
2016-03-10 08:32:49 +03:00
|
|
|
ISEQ_COVERAGE_SET(iseq, coverage);
|
2018-10-20 13:45:48 +03:00
|
|
|
if (coverage && ISEQ_BRANCH_COVERAGE(iseq))
|
|
|
|
ISEQ_PC2BRANCHINDEX_SET(iseq, rb_ary_tmp_new(0));
|
2008-07-01 20:55:30 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
2018-01-01 16:18:55 +03:00
|
|
|
#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
|
2018-03-21 05:20:37 +03:00
|
|
|
static void validate_get_insn_info(const rb_iseq_t *iseq);
|
2017-12-20 10:38:24 +03:00
|
|
|
#endif
|
|
|
|
|
2018-01-09 17:05:23 +03:00
|
|
|
void
|
|
|
|
rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2
|
2018-05-12 04:24:18 +03:00
|
|
|
struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
int size = body->insns_info.size;
|
|
|
|
int max_pos = body->iseq_size;
|
|
|
|
int *data = (int *)body->insns_info.positions;
|
|
|
|
if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
|
|
|
|
body->insns_info.succ_index_table = succ_index_table_create(max_pos, data, size);
|
2018-01-09 17:05:23 +03:00
|
|
|
#if VM_CHECK_MODE == 0
|
2018-05-12 04:24:18 +03:00
|
|
|
ruby_xfree(body->insns_info.positions);
|
|
|
|
body->insns_info.positions = NULL;
|
2018-01-09 17:05:23 +03:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-06-13 07:51:43 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2
|
2018-04-05 10:04:39 +03:00
|
|
|
unsigned int *
|
|
|
|
rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body)
|
2018-01-09 17:05:23 +03:00
|
|
|
{
|
2018-04-05 10:04:39 +03:00
|
|
|
int size = body->insns_info.size;
|
|
|
|
int max_pos = body->iseq_size;
|
|
|
|
struct succ_index_table *sd = body->insns_info.succ_index_table;
|
|
|
|
return succ_index_table_invert(max_pos, sd, size);
|
2018-01-09 17:05:23 +03:00
|
|
|
}
|
2018-06-13 07:51:43 +03:00
|
|
|
#endif
|
2018-01-09 17:05:23 +03:00
|
|
|
|
2018-08-23 07:12:14 +03:00
|
|
|
void
|
2018-09-13 16:59:25 +03:00
|
|
|
rb_iseq_init_trace(rb_iseq_t *iseq)
|
2018-08-23 07:12:14 +03:00
|
|
|
{
|
2018-12-06 13:52:27 +03:00
|
|
|
iseq->aux.exec.global_trace_events = 0;
|
2018-11-26 21:16:39 +03:00
|
|
|
if (ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS) {
|
|
|
|
rb_iseq_trace_set(iseq, ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS);
|
2018-08-23 07:12:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2017-11-14 15:58:36 +03:00
|
|
|
finish_iseq_build(rb_iseq_t *iseq)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-12-02 10:52:12 +03:00
|
|
|
struct iseq_compile_data *data = ISEQ_COMPILE_DATA(iseq);
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
* include/ruby/{intern,ruby}.h, compile.[ch], error.c, eval.c,
eval_load.c, gc.c, iseq.c, main.c, parse.y, re.c, ruby.c,
yarvcore.[ch] (ruby_eval_tree, ruby_sourcefile, ruby_sourceline,
ruby_nerrs): purge global variables.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12700 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-05 12:12:18 +04:00
|
|
|
VALUE err = data->err_info;
|
2017-11-18 12:39:41 +03:00
|
|
|
ISEQ_COMPILE_DATA_CLEAR(iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
compile_data_free(data);
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2018-01-09 17:05:23 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2 /* succinct bitvector */
|
|
|
|
/* create succ_index_table */
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->insns_info.succ_index_table == NULL) {
|
2018-01-09 17:05:23 +03:00
|
|
|
rb_iseq_insns_info_encode_positions(iseq);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-01-01 16:18:55 +03:00
|
|
|
#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
|
2017-12-20 10:38:24 +03:00
|
|
|
validate_get_insn_info(iseq);
|
|
|
|
#endif
|
|
|
|
|
* include/ruby/{intern,ruby}.h, compile.[ch], error.c, eval.c,
eval_load.c, gc.c, iseq.c, main.c, parse.y, re.c, ruby.c,
yarvcore.[ch] (ruby_eval_tree, ruby_sourcefile, ruby_sourceline,
ruby_nerrs): purge global variables.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12700 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-05 12:12:18 +04:00
|
|
|
if (RTEST(err)) {
|
2018-05-12 04:24:18 +03:00
|
|
|
VALUE path = pathobj_path(body->location.pathobj);
|
2017-01-12 10:41:35 +03:00
|
|
|
if (err == Qtrue) err = rb_exc_new_cstr(rb_eSyntaxError, "compile error");
|
2017-06-01 03:05:33 +03:00
|
|
|
rb_funcallv(err, rb_intern("set_backtrace"), 1, &path);
|
* include/ruby/{intern,ruby}.h, compile.[ch], error.c, eval.c,
eval_load.c, gc.c, iseq.c, main.c, parse.y, re.c, ruby.c,
yarvcore.[ch] (ruby_eval_tree, ruby_sourcefile, ruby_sourceline,
ruby_nerrs): purge global variables.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12700 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-05 12:12:18 +04:00
|
|
|
rb_exc_raise(err);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2017-11-14 15:58:36 +03:00
|
|
|
|
2018-09-13 16:59:25 +03:00
|
|
|
rb_iseq_init_trace(iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
* 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
|
|
|
static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
|
2006-12-31 18:02:22 +03:00
|
|
|
OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
|
|
|
|
OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
|
2007-05-21 08:46:51 +04:00
|
|
|
OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
|
2006-12-31 18:02:22 +03:00
|
|
|
OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
|
|
|
|
OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
|
|
|
|
OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
|
|
|
|
OPT_STACK_CACHING, /* int stack_caching; */
|
2015-10-23 22:13:51 +03:00
|
|
|
OPT_FROZEN_STRING_LITERAL,
|
2015-11-25 11:02:29 +03:00
|
|
|
OPT_DEBUG_FROZEN_STRING_LITERAL,
|
2016-03-10 11:34:18 +03:00
|
|
|
TRUE, /* coverage_enabled */
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
2015-08-21 23:47:53 +03:00
|
|
|
|
2008-07-01 12:44:32 +04:00
|
|
|
static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-09-27 09:44:02 +03:00
|
|
|
static void
|
|
|
|
set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
|
|
|
|
{
|
|
|
|
#define SET_COMPILE_OPTION(o, h, mem) \
|
|
|
|
{ VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
|
|
|
|
if (flag == Qtrue) { (o)->mem = 1; } \
|
|
|
|
else if (flag == Qfalse) { (o)->mem = 0; } \
|
|
|
|
}
|
|
|
|
#define SET_COMPILE_OPTION_NUM(o, h, mem) \
|
|
|
|
{ VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
|
|
|
|
if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
|
|
|
|
}
|
|
|
|
SET_COMPILE_OPTION(option, opt, inline_const_cache);
|
|
|
|
SET_COMPILE_OPTION(option, opt, peephole_optimization);
|
|
|
|
SET_COMPILE_OPTION(option, opt, tailcall_optimization);
|
|
|
|
SET_COMPILE_OPTION(option, opt, specialized_instruction);
|
|
|
|
SET_COMPILE_OPTION(option, opt, operands_unification);
|
|
|
|
SET_COMPILE_OPTION(option, opt, instructions_unification);
|
|
|
|
SET_COMPILE_OPTION(option, opt, stack_caching);
|
|
|
|
SET_COMPILE_OPTION(option, opt, frozen_string_literal);
|
2015-11-25 11:02:29 +03:00
|
|
|
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
|
2016-03-10 11:34:18 +03:00
|
|
|
SET_COMPILE_OPTION(option, opt, coverage_enabled);
|
2015-09-27 09:44:02 +03:00
|
|
|
SET_COMPILE_OPTION_NUM(option, opt, debug_level);
|
|
|
|
#undef SET_COMPILE_OPTION
|
|
|
|
#undef SET_COMPILE_OPTION_NUM
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_iseq_make_compile_option(rb_compile_option_t *option, VALUE opt)
|
|
|
|
{
|
|
|
|
Check_Type(opt, T_HASH);
|
|
|
|
set_compile_option_from_hash(option, opt);
|
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
static void
|
* 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
|
|
|
make_compile_option(rb_compile_option_t *option, VALUE opt)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
if (opt == Qnil) {
|
|
|
|
*option = COMPILE_OPTION_DEFAULT;
|
|
|
|
}
|
|
|
|
else if (opt == Qfalse) {
|
|
|
|
*option = COMPILE_OPTION_FALSE;
|
|
|
|
}
|
|
|
|
else if (opt == Qtrue) {
|
2013-11-15 12:07:35 +04:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < (int)(sizeof(rb_compile_option_t) / sizeof(int)); ++i)
|
|
|
|
((int *)option)[i] = 1;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2015-12-28 09:42:18 +03:00
|
|
|
else if (RB_TYPE_P(opt, T_HASH)) {
|
2007-05-21 08:46:51 +04:00
|
|
|
*option = COMPILE_OPTION_DEFAULT;
|
2015-09-27 09:44:02 +03:00
|
|
|
set_compile_option_from_hash(option, opt);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
* 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
|
|
|
make_compile_option_value(rb_compile_option_t *option)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
VALUE opt = rb_hash_new();
|
|
|
|
#define SET_COMPILE_OPTION(o, h, mem) \
|
2010-12-17 01:05:58 +03:00
|
|
|
rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
|
2008-04-14 09:34:04 +04:00
|
|
|
#define SET_COMPILE_OPTION_NUM(o, h, mem) \
|
2010-12-17 01:05:58 +03:00
|
|
|
rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
SET_COMPILE_OPTION(option, opt, inline_const_cache);
|
|
|
|
SET_COMPILE_OPTION(option, opt, peephole_optimization);
|
2007-05-21 08:46:51 +04:00
|
|
|
SET_COMPILE_OPTION(option, opt, tailcall_optimization);
|
2006-12-31 18:02:22 +03:00
|
|
|
SET_COMPILE_OPTION(option, opt, specialized_instruction);
|
|
|
|
SET_COMPILE_OPTION(option, opt, operands_unification);
|
|
|
|
SET_COMPILE_OPTION(option, opt, instructions_unification);
|
|
|
|
SET_COMPILE_OPTION(option, opt, stack_caching);
|
2015-10-23 22:13:51 +03:00
|
|
|
SET_COMPILE_OPTION(option, opt, frozen_string_literal);
|
2015-11-25 11:02:29 +03:00
|
|
|
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
|
2016-03-10 11:34:18 +03:00
|
|
|
SET_COMPILE_OPTION(option, opt, coverage_enabled);
|
2008-04-14 09:34:04 +04:00
|
|
|
SET_COMPILE_OPTION_NUM(option, opt, debug_level);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
#undef SET_COMPILE_OPTION
|
2008-04-14 09:34:04 +04:00
|
|
|
#undef SET_COMPILE_OPTION_NUM
|
2006-12-31 18:02:22 +03:00
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
2018-01-05 11:59:22 +03:00
|
|
|
rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *parent, enum iseq_type type)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2018-01-05 11:59:22 +03:00
|
|
|
return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, type,
|
* 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
|
|
|
&COMPILE_OPTION_DEFAULT);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
2018-01-05 11:59:22 +03:00
|
|
|
rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
|
* include/ruby/node.h, vm_core.h: move definition of
RUBY_VM_METHOD_NODE to node.h.
* class.c, common.mk: remove useless inclusion.
* compile.h, iseq.h, vm_core.h: rename compile.h to iseq.h.
move some definitions from vm_core.h to iseq.h.
* compile.c, iseq.c, vm.c: ditto.
* eval.c, compile.c: move some functions for parser
from eval.c to compile.c.
* eval_intern.h, vm_core.h: move va_init_list() macro to
vm_core.h.
* iseq.c (rb_iseq_new_top, rb_iseq_first_lineno): added.
* load.c, ruby.c: use rb_iseq_new_top() instead of
rb_iseq_new() with ISEQ_TYPE_TOP constant directly.
* proc.c: use rb_iseq_first_lineno() instead of accessing
iseq structure.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19472 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 11:49:45 +04:00
|
|
|
{
|
2018-08-22 13:38:56 +03:00
|
|
|
VALUE coverages = rb_get_coverages();
|
|
|
|
if (RTEST(coverages)) {
|
|
|
|
if (ast->line_count >= 0) {
|
2018-10-20 08:33:04 +03:00
|
|
|
int len = (rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES) ? 0 : ast->line_count;
|
|
|
|
VALUE coverage = rb_default_coverage(len);
|
2018-08-22 13:38:56 +03:00
|
|
|
rb_hash_aset(coverages, path, coverage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-05 11:59:22 +03:00
|
|
|
return rb_iseq_new_with_opt(ast, name, path, realpath, INT2FIX(0), parent, ISEQ_TYPE_TOP,
|
* include/ruby/node.h, vm_core.h: move definition of
RUBY_VM_METHOD_NODE to node.h.
* class.c, common.mk: remove useless inclusion.
* compile.h, iseq.h, vm_core.h: rename compile.h to iseq.h.
move some definitions from vm_core.h to iseq.h.
* compile.c, iseq.c, vm.c: ditto.
* eval.c, compile.c: move some functions for parser
from eval.c to compile.c.
* eval_intern.h, vm_core.h: move va_init_list() macro to
vm_core.h.
* iseq.c (rb_iseq_new_top, rb_iseq_first_lineno): added.
* load.c, ruby.c: use rb_iseq_new_top() instead of
rb_iseq_new() with ISEQ_TYPE_TOP constant directly.
* proc.c: use rb_iseq_first_lineno() instead of accessing
iseq structure.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19472 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 11:49:45 +04:00
|
|
|
&COMPILE_OPTION_DEFAULT);
|
2008-12-27 04:15:56 +03:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
2018-01-05 11:59:22 +03:00
|
|
|
rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent)
|
2008-12-27 04:15:56 +03:00
|
|
|
{
|
2018-10-13 12:59:22 +03:00
|
|
|
return rb_iseq_new_with_opt(ast, rb_fstring_lit("<main>"),
|
2017-06-01 03:05:33 +03:00
|
|
|
path, realpath, INT2FIX(0),
|
2008-12-27 08:58:23 +03:00
|
|
|
parent, ISEQ_TYPE_MAIN, &COMPILE_OPTION_DEFAULT);
|
* include/ruby/node.h, vm_core.h: move definition of
RUBY_VM_METHOD_NODE to node.h.
* class.c, common.mk: remove useless inclusion.
* compile.h, iseq.h, vm_core.h: rename compile.h to iseq.h.
move some definitions from vm_core.h to iseq.h.
* compile.c, iseq.c, vm.c: ditto.
* eval.c, compile.c: move some functions for parser
from eval.c to compile.c.
* eval_intern.h, vm_core.h: move va_init_list() macro to
vm_core.h.
* iseq.c (rb_iseq_new_top, rb_iseq_first_lineno): added.
* load.c, ruby.c: use rb_iseq_new_top() instead of
rb_iseq_new() with ISEQ_TYPE_TOP constant directly.
* proc.c: use rb_iseq_first_lineno() instead of accessing
iseq structure.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19472 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 11:49:45 +04:00
|
|
|
}
|
|
|
|
|
2015-12-07 20:23:18 +03:00
|
|
|
static inline rb_iseq_t *
|
|
|
|
iseq_translate(rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
if (rb_respond_to(rb_cISeq, rb_intern("translate"))) {
|
|
|
|
VALUE v1 = iseqw_new(iseq);
|
|
|
|
VALUE v2 = rb_funcall(rb_cISeq, rb_intern("translate"), 1, v1);
|
|
|
|
if (v1 != v2 && CLASS_OF(v2) == rb_cISeq) {
|
|
|
|
iseq = (rb_iseq_t *)iseqw_check(v2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return iseq;
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
2018-01-05 11:59:22 +03:00
|
|
|
rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
|
2015-07-22 01:52:59 +03:00
|
|
|
VALUE first_lineno, const rb_iseq_t *parent,
|
|
|
|
enum iseq_type type, const rb_compile_option_t *option)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2018-01-05 11:59:22 +03:00
|
|
|
const NODE *node = ast ? ast->root : 0;
|
2014-12-05 05:10:29 +03:00
|
|
|
/* TODO: argument check */
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *iseq = iseq_alloc();
|
2018-01-05 11:59:23 +03:00
|
|
|
rb_compile_option_t new_opt;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-01-05 11:59:23 +03:00
|
|
|
new_opt = option ? *option : COMPILE_OPTION_DEFAULT;
|
|
|
|
if (ast && ast->compile_option) rb_iseq_make_compile_option(&new_opt, ast->compile_option);
|
|
|
|
|
2018-11-05 05:13:45 +03:00
|
|
|
prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1, parent, type, &new_opt);
|
2014-12-05 05:10:29 +03:00
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_compile_node(iseq, node);
|
2017-11-14 15:58:36 +03:00
|
|
|
finish_iseq_build(iseq);
|
2015-07-22 01:52:59 +03:00
|
|
|
|
2015-12-07 20:23:18 +03:00
|
|
|
return iseq_translate(iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2018-01-04 10:07:49 +03:00
|
|
|
rb_iseq_t *
|
|
|
|
rb_iseq_new_ifunc(const struct vm_ifunc *ifunc, VALUE name, VALUE path, VALUE realpath,
|
|
|
|
VALUE first_lineno, const rb_iseq_t *parent,
|
|
|
|
enum iseq_type type, const rb_compile_option_t *option)
|
|
|
|
{
|
|
|
|
/* TODO: argument check */
|
|
|
|
rb_iseq_t *iseq = iseq_alloc();
|
|
|
|
|
|
|
|
if (!option) option = &COMPILE_OPTION_DEFAULT;
|
2018-11-05 05:13:45 +03:00
|
|
|
prepare_iseq_build(iseq, name, path, realpath, first_lineno, NULL, -1, parent, type, option);
|
2018-01-04 10:07:49 +03:00
|
|
|
|
|
|
|
rb_iseq_compile_ifunc(iseq, ifunc);
|
|
|
|
finish_iseq_build(iseq);
|
|
|
|
|
|
|
|
return iseq_translate(iseq);
|
|
|
|
}
|
|
|
|
|
2015-12-08 16:58:50 +03:00
|
|
|
const rb_iseq_t *
|
|
|
|
rb_iseq_load_iseq(VALUE fname)
|
|
|
|
{
|
2015-12-12 10:07:42 +03:00
|
|
|
VALUE iseqv = rb_check_funcall(rb_cISeq, rb_intern("load_iseq"), 1, &fname);
|
|
|
|
|
|
|
|
if (!SPECIAL_CONST_P(iseqv) && RBASIC_CLASS(iseqv) == rb_cISeq) {
|
|
|
|
return iseqw_check(iseqv);
|
2015-12-08 16:58:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-10-26 10:23:23 +03:00
|
|
|
#define CHECK_ARRAY(v) rb_to_array_type(v)
|
|
|
|
#define CHECK_HASH(v) rb_to_hash_type(v)
|
|
|
|
#define CHECK_STRING(v) rb_str_to_str(v)
|
|
|
|
#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
|
2010-07-27 11:13:43 +04:00
|
|
|
static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
|
2014-01-12 11:49:26 +04:00
|
|
|
|
|
|
|
static enum iseq_type
|
2014-07-28 12:15:42 +04:00
|
|
|
iseq_type_from_sym(VALUE type)
|
2014-01-12 11:49:26 +04:00
|
|
|
{
|
2014-07-28 12:15:42 +04:00
|
|
|
const ID id_top = rb_intern("top");
|
|
|
|
const ID id_method = rb_intern("method");
|
|
|
|
const ID id_block = rb_intern("block");
|
|
|
|
const ID id_class = rb_intern("class");
|
|
|
|
const ID id_rescue = rb_intern("rescue");
|
|
|
|
const ID id_ensure = rb_intern("ensure");
|
|
|
|
const ID id_eval = rb_intern("eval");
|
|
|
|
const ID id_main = rb_intern("main");
|
2018-01-05 03:49:41 +03:00
|
|
|
const ID id_plain = rb_intern("plain");
|
2014-07-28 12:15:42 +04:00
|
|
|
/* ensure all symbols are static or pinned down before
|
|
|
|
* conversion */
|
|
|
|
const ID typeid = rb_check_id(&type);
|
|
|
|
if (typeid == id_top) return ISEQ_TYPE_TOP;
|
|
|
|
if (typeid == id_method) return ISEQ_TYPE_METHOD;
|
|
|
|
if (typeid == id_block) return ISEQ_TYPE_BLOCK;
|
|
|
|
if (typeid == id_class) return ISEQ_TYPE_CLASS;
|
|
|
|
if (typeid == id_rescue) return ISEQ_TYPE_RESCUE;
|
|
|
|
if (typeid == id_ensure) return ISEQ_TYPE_ENSURE;
|
|
|
|
if (typeid == id_eval) return ISEQ_TYPE_EVAL;
|
|
|
|
if (typeid == id_main) return ISEQ_TYPE_MAIN;
|
2018-01-05 03:49:41 +03:00
|
|
|
if (typeid == id_plain) return ISEQ_TYPE_PLAIN;
|
2014-01-12 11:49:26 +04:00
|
|
|
return (enum iseq_type)-1;
|
|
|
|
}
|
|
|
|
|
2008-12-05 06:35:48 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *iseq = iseq_alloc();
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
VALUE magic, version1, version2, format_type, misc;
|
2018-11-05 05:13:45 +03:00
|
|
|
VALUE name, path, realpath, first_lineno, code_location, node_id;
|
2014-12-04 01:16:58 +03:00
|
|
|
VALUE type, body, locals, params, exception;
|
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 iseq_type;
|
* 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
|
|
|
rb_compile_option_t option;
|
2008-01-08 07:05:59 +03:00
|
|
|
int i = 0;
|
2018-01-09 11:45:35 +03:00
|
|
|
rb_code_location_t tmp_loc = { {0, 0}, {-1, -1} };
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
/* [magic, major_version, minor_version, format_type, misc,
|
2012-06-04 06:49:37 +04:00
|
|
|
* label, path, first_lineno,
|
2006-12-31 18:02:22 +03:00
|
|
|
* type, locals, args, exception_table, body]
|
|
|
|
*/
|
|
|
|
|
|
|
|
data = CHECK_ARRAY(data);
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2008-01-08 07:05:59 +03:00
|
|
|
magic = CHECK_STRING(rb_ary_entry(data, i++));
|
|
|
|
version1 = CHECK_INTEGER(rb_ary_entry(data, i++));
|
|
|
|
version2 = CHECK_INTEGER(rb_ary_entry(data, i++));
|
|
|
|
format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
|
2014-12-04 01:16:58 +03:00
|
|
|
misc = CHECK_HASH(rb_ary_entry(data, i++));
|
|
|
|
((void)magic, (void)version1, (void)version2, (void)format_type);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2008-01-08 07:05:59 +03:00
|
|
|
name = CHECK_STRING(rb_ary_entry(data, i++));
|
2012-06-04 06:49:37 +04:00
|
|
|
path = CHECK_STRING(rb_ary_entry(data, i++));
|
2017-06-01 03:05:33 +03:00
|
|
|
realpath = rb_ary_entry(data, i++);
|
|
|
|
realpath = NIL_P(realpath) ? Qnil : CHECK_STRING(realpath);
|
2012-06-04 06:49:37 +04:00
|
|
|
first_lineno = CHECK_INTEGER(rb_ary_entry(data, i++));
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2008-01-08 07:05:59 +03:00
|
|
|
type = CHECK_SYMBOL(rb_ary_entry(data, i++));
|
|
|
|
locals = CHECK_ARRAY(rb_ary_entry(data, i++));
|
2014-12-04 01:16:58 +03:00
|
|
|
params = CHECK_HASH(rb_ary_entry(data, i++));
|
2008-01-08 07:05:59 +03:00
|
|
|
exception = CHECK_ARRAY(rb_ary_entry(data, i++));
|
|
|
|
body = CHECK_ARRAY(rb_ary_entry(data, i++));
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
iseq->body->local_iseq = iseq;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2014-07-28 12:15:42 +04:00
|
|
|
iseq_type = iseq_type_from_sym(type);
|
2014-01-12 11:49:26 +04:00
|
|
|
if (iseq_type == (enum iseq_type)-1) {
|
2014-07-28 12:15:42 +04:00
|
|
|
rb_raise(rb_eTypeError, "unsupport type: :%"PRIsVALUE, rb_sym2str(type));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2018-11-05 05:13:45 +03:00
|
|
|
node_id = rb_hash_aref(misc, ID2SYM(rb_intern("node_id")));
|
|
|
|
|
2018-01-09 11:45:35 +03:00
|
|
|
code_location = rb_hash_aref(misc, ID2SYM(rb_intern("code_location")));
|
|
|
|
if (RB_TYPE_P(code_location, T_ARRAY) && RARRAY_LEN(code_location) == 4) {
|
|
|
|
tmp_loc.beg_pos.lineno = NUM2INT(rb_ary_entry(code_location, 0));
|
|
|
|
tmp_loc.beg_pos.column = NUM2INT(rb_ary_entry(code_location, 1));
|
|
|
|
tmp_loc.end_pos.lineno = NUM2INT(rb_ary_entry(code_location, 2));
|
|
|
|
tmp_loc.end_pos.column = NUM2INT(rb_ary_entry(code_location, 3));
|
2017-12-05 11:56:50 +03:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
make_compile_option(&option, opt);
|
2015-12-07 21:46:27 +03:00
|
|
|
option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */
|
2018-11-05 05:13:45 +03:00
|
|
|
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, NUM2INT(node_id),
|
2014-12-05 05:10:29 +03:00
|
|
|
parent, (enum iseq_type)iseq_type, &option);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2014-12-04 01:16:58 +03:00
|
|
|
rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2017-11-14 15:58:36 +03:00
|
|
|
finish_iseq_build(iseq);
|
2015-07-22 01:52:59 +03:00
|
|
|
|
|
|
|
return iseqw_new(iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* :nodoc:
|
|
|
|
*/
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
|
|
|
iseq_s_load(int argc, VALUE *argv, VALUE self)
|
|
|
|
{
|
|
|
|
VALUE data, opt=Qnil;
|
2015-12-08 17:05:44 +03:00
|
|
|
rb_scan_args(argc, argv, "11", &data, &opt);
|
2015-07-22 01:52:59 +03:00
|
|
|
return iseq_load(data, NULL, opt);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2008-12-05 06:35:48 +03:00
|
|
|
VALUE
|
* iseq.c (rb_iseq_load): renamed from ruby_iseq_load, since it is
for C extensions or the ruby core. [ruby-core:21407]
Index: compile.c
===================================================================
--- compile.c (revision 21649)
+++ compile.c (working copy)
@@ -5078,5 +5078,5 @@ iseq_build_exception(rb_iseq_t *iseq, st
}
else {
- eiseqval = ruby_iseq_load(ptr[1], iseq->self, Qnil);
+ eiseqval = rb_iseq_load(ptr[1], iseq->self, Qnil);
}
@@ -5162,5 +5162,5 @@ iseq_build_body(rb_iseq_t *iseq, LINK_AN
if (op != Qnil) {
if (TYPE(op) == T_ARRAY) {
- argv[j] = ruby_iseq_load(op, iseq->self, Qnil);
+ argv[j] = rb_iseq_load(op, iseq->self, Qnil);
}
else if (CLASS_OF(op) == rb_cISeq) {
Index: iseq.c
===================================================================
--- iseq.c (revision 21649)
+++ iseq.c (working copy)
@@ -448,5 +448,5 @@ iseq_s_load(int argc, VALUE *argv, VALUE
VALUE
-ruby_iseq_load(VALUE data, VALUE parent, VALUE opt)
+rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
{
return iseq_load(rb_cISeq, data, parent, opt);
Index: iseq.h
===================================================================
--- iseq.h (revision 21649)
+++ iseq.h (working copy)
@@ -21,5 +21,5 @@ VALUE ruby_iseq_build_from_ary(rb_iseq_t
/* iseq.c */
-VALUE ruby_iseq_load(VALUE data, VALUE parent, VALUE opt);
+VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
struct st_table *ruby_insn_make_insn_table(void);
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21650 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-01-18 22:05:15 +03:00
|
|
|
rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
|
2008-12-05 06:35:48 +03:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
return iseq_load(data, RTEST(parent) ? (rb_iseq_t *)parent : NULL, opt);
|
2008-12-05 06:35:48 +03:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
2017-06-01 03:05:33 +03:00
|
|
|
rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, const struct rb_block *base_block, VALUE opt)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *iseq = NULL;
|
2016-07-28 14:02:30 +03:00
|
|
|
const rb_iseq_t *const parent = base_block ? vm_block_iseq(base_block) : NULL;
|
2015-12-24 17:15:14 +03:00
|
|
|
rb_compile_option_t option;
|
2015-12-28 09:42:18 +03:00
|
|
|
const enum iseq_type type = parent ? ISEQ_TYPE_EVAL : ISEQ_TYPE_TOP;
|
2016-01-08 13:52:24 +03:00
|
|
|
#if !defined(__GNUC__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 8)
|
2016-01-08 10:47:49 +03:00
|
|
|
# define INITIALIZED volatile /* suppress warnings by gcc 4.8 */
|
|
|
|
#else
|
2016-01-08 13:52:24 +03:00
|
|
|
# define INITIALIZED /* volatile */
|
2016-01-08 10:47:49 +03:00
|
|
|
#endif
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_t *(*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
|
2016-03-29 00:39:24 +03:00
|
|
|
int ln;
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_t *INITIALIZED ast;
|
2016-03-29 00:39:24 +03:00
|
|
|
|
2016-01-08 10:47:49 +03:00
|
|
|
/* safe results first */
|
2016-03-29 00:39:24 +03:00
|
|
|
make_compile_option(&option, opt);
|
|
|
|
ln = NUM2INT(line);
|
|
|
|
StringValueCStr(file);
|
|
|
|
if (RB_TYPE_P(src, T_FILE)) {
|
|
|
|
parse = rb_parser_compile_file_path;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
parse = rb_parser_compile_string_path;
|
|
|
|
StringValue(src);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
const VALUE parser = rb_parser_new();
|
|
|
|
rb_parser_set_context(parser, base_block, FALSE);
|
2017-10-27 19:44:57 +03:00
|
|
|
ast = (*parse)(parser, file, src, ln);
|
2016-03-29 00:39:24 +03:00
|
|
|
}
|
|
|
|
|
2018-01-05 11:59:20 +03:00
|
|
|
if (!ast->body.root) {
|
2017-10-27 19:44:57 +03:00
|
|
|
rb_ast_dispose(ast);
|
2017-11-07 08:08:09 +03:00
|
|
|
rb_exc_raise(GET_EC()->errinfo);
|
2016-03-29 00:39:24 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
INITIALIZED VALUE label = parent ?
|
|
|
|
parent->body->location.label :
|
2018-10-13 12:59:22 +03:00
|
|
|
rb_fstring_lit("<compiled>");
|
2018-01-05 11:59:22 +03:00
|
|
|
iseq = rb_iseq_new_with_opt(&ast->body, label, file, realpath, line,
|
2016-03-29 00:40:55 +03:00
|
|
|
parent, type, &option);
|
2017-10-27 19:44:57 +03:00
|
|
|
rb_ast_dispose(ast);
|
* 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
|
|
|
}
|
* iseq.c, vm_eval.c: set th->base_block properly.
th->base_block is information for (a) parsing, (b) compiling
and (c) setting up the frame to execute the program passed by
`eval' method. For example, (1) parser need to know up-level
variables to detect it is variable or method without paren.
Befor (a), (b) and (c), VM set th->base_block by passed bindng
(or previous frame information). After execute (a), (b) and (c),
VM should clear th->base_block. However, if (a), (b) or (c)
raises an exception, then th->base_block is not cleared.
Problem is that the uncleared value th->balo_block is used for
irrelevant iseq compilation. It causes SEGV or critical error.
I tried to solve this problem: to clear them before exception,
but finally I found out that it is difficult to do it (Ruby
program can be run in many places).
Because of this background, I set th->base_block before
compiling iseq and restore it after compiling.
Basically, th->base_block is dirty hack (similar to global
variable) and this patch is also dirty.
* bootstraptest/test_eval.rb: add a test for above.
* internal.h: remove unused decl.
* iseq.c (rb_iseq_compile_with_option): add base_block parameter.
set th->base_block before compation and restore it after
compilation.
* ruby.c (require_libraries): pass 0 as base_block instead of
setting th->base_block
* tool/compile_prelude.rb (prelude_eval): apply above changes.
* vm.c, vm_eval.c: ditto.
* vm_core.h: add comments.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36179 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-22 13:32:56 +04:00
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
return iseq;
|
* 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-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
* 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_iseq_compile(VALUE src, VALUE file, VALUE line)
|
|
|
|
{
|
* iseq.c, vm_eval.c: set th->base_block properly.
th->base_block is information for (a) parsing, (b) compiling
and (c) setting up the frame to execute the program passed by
`eval' method. For example, (1) parser need to know up-level
variables to detect it is variable or method without paren.
Befor (a), (b) and (c), VM set th->base_block by passed bindng
(or previous frame information). After execute (a), (b) and (c),
VM should clear th->base_block. However, if (a), (b) or (c)
raises an exception, then th->base_block is not cleared.
Problem is that the uncleared value th->balo_block is used for
irrelevant iseq compilation. It causes SEGV or critical error.
I tried to solve this problem: to clear them before exception,
but finally I found out that it is difficult to do it (Ruby
program can be run in many places).
Because of this background, I set th->base_block before
compiling iseq and restore it after compiling.
Basically, th->base_block is dirty hack (similar to global
variable) and this patch is also dirty.
* bootstraptest/test_eval.rb: add a test for above.
* internal.h: remove unused decl.
* iseq.c (rb_iseq_compile_with_option): add base_block parameter.
set th->base_block before compation and restore it after
compilation.
* ruby.c (require_libraries): pass 0 as base_block instead of
setting th->base_block
* tool/compile_prelude.rb (prelude_eval): apply above changes.
* vm.c, vm_eval.c: ditto.
* vm_core.h: add comments.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36179 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-22 13:32:56 +04:00
|
|
|
return rb_iseq_compile_with_option(src, file, Qnil, line, 0, Qnil);
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_iseq_t *
|
2016-07-28 14:02:30 +03:00
|
|
|
rb_iseq_compile_on_base(VALUE src, VALUE file, VALUE line, const struct rb_block *base_block)
|
* iseq.c, vm_eval.c: set th->base_block properly.
th->base_block is information for (a) parsing, (b) compiling
and (c) setting up the frame to execute the program passed by
`eval' method. For example, (1) parser need to know up-level
variables to detect it is variable or method without paren.
Befor (a), (b) and (c), VM set th->base_block by passed bindng
(or previous frame information). After execute (a), (b) and (c),
VM should clear th->base_block. However, if (a), (b) or (c)
raises an exception, then th->base_block is not cleared.
Problem is that the uncleared value th->balo_block is used for
irrelevant iseq compilation. It causes SEGV or critical error.
I tried to solve this problem: to clear them before exception,
but finally I found out that it is difficult to do it (Ruby
program can be run in many places).
Because of this background, I set th->base_block before
compiling iseq and restore it after compiling.
Basically, th->base_block is dirty hack (similar to global
variable) and this patch is also dirty.
* bootstraptest/test_eval.rb: add a test for above.
* internal.h: remove unused decl.
* iseq.c (rb_iseq_compile_with_option): add base_block parameter.
set th->base_block before compation and restore it after
compilation.
* ruby.c (require_libraries): pass 0 as base_block instead of
setting th->base_block
* tool/compile_prelude.rb (prelude_eval): apply above changes.
* vm.c, vm_eval.c: ditto.
* vm_core.h: add comments.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36179 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-06-22 13:32:56 +04:00
|
|
|
{
|
|
|
|
return rb_iseq_compile_with_option(src, file, Qnil, line, base_block, Qnil);
|
* 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
|
|
|
}
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
VALUE
|
|
|
|
rb_iseq_path(const rb_iseq_t *iseq)
|
|
|
|
{
|
2017-06-01 03:05:33 +03:00
|
|
|
return pathobj_path(iseq->body->location.pathobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseq_realpath(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return pathobj_realpath(iseq->body->location.pathobj);
|
2015-07-22 01:52:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseq_absolute_path(const rb_iseq_t *iseq)
|
|
|
|
{
|
2017-06-01 03:05:33 +03:00
|
|
|
return rb_iseq_realpath(iseq);
|
2015-07-22 01:52:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseq_label(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return iseq->body->location.label;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseq_base_label(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return iseq->body->location.base_label;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseq_first_lineno(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return iseq->body->location.first_lineno;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseq_method_name(const rb_iseq_t *iseq)
|
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
struct rb_iseq_constant_body *const body = iseq->body->local_iseq->body;
|
2015-07-22 01:52:59 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->type == ISEQ_TYPE_METHOD) {
|
|
|
|
return body->location.base_label;
|
2015-07-22 01:52:59 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 09:40:28 +03:00
|
|
|
void
|
2018-01-09 11:45:35 +03:00
|
|
|
rb_iseq_code_location(const rb_iseq_t *iseq, int *beg_pos_lineno, int *beg_pos_column, int *end_pos_lineno, int *end_pos_column)
|
2017-12-21 09:40:28 +03:00
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const rb_code_location_t *loc = &iseq->body->location.code_location;
|
|
|
|
if (beg_pos_lineno) *beg_pos_lineno = loc->beg_pos.lineno;
|
|
|
|
if (beg_pos_column) *beg_pos_column = loc->beg_pos.column;
|
|
|
|
if (end_pos_lineno) *end_pos_lineno = loc->end_pos.lineno;
|
|
|
|
if (end_pos_column) *end_pos_column = loc->end_pos.column;
|
2017-12-21 09:40:28 +03:00
|
|
|
}
|
|
|
|
|
2015-12-02 11:05:36 +03:00
|
|
|
VALUE
|
|
|
|
rb_iseq_coverage(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return ISEQ_COVERAGE(iseq);
|
|
|
|
}
|
|
|
|
|
2018-08-22 08:24:50 +03:00
|
|
|
static int
|
|
|
|
remove_coverage_i(void *vstart, void *vend, size_t stride, void *data)
|
|
|
|
{
|
|
|
|
VALUE v = (VALUE)vstart;
|
|
|
|
for (; v != (VALUE)vend; v += stride) {
|
2019-05-23 11:02:07 +03:00
|
|
|
void *ptr = asan_poisoned_object_p(v);
|
|
|
|
asan_unpoison_object(v, false);
|
2019-04-02 01:52:35 +03:00
|
|
|
|
2018-08-22 08:24:50 +03:00
|
|
|
if (rb_obj_is_iseq(v)) {
|
|
|
|
rb_iseq_t *iseq = (rb_iseq_t *)v;
|
|
|
|
ISEQ_COVERAGE_SET(iseq, Qnil);
|
|
|
|
}
|
2019-04-02 01:52:35 +03:00
|
|
|
|
2019-05-29 07:12:15 +03:00
|
|
|
asan_poison_object_if(ptr, v);
|
2018-08-22 08:24:50 +03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-08-22 13:22:02 +03:00
|
|
|
rb_iseq_remove_coverage_all(void)
|
2018-08-22 08:24:50 +03:00
|
|
|
{
|
|
|
|
rb_objspace_each_objects(remove_coverage_i, NULL);
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
/* define wrapper class methods (RubyVM::InstructionSequence) */
|
|
|
|
|
2015-08-12 15:18:51 +03:00
|
|
|
static void
|
|
|
|
iseqw_mark(void *ptr)
|
|
|
|
{
|
|
|
|
rb_gc_mark((VALUE)ptr);
|
|
|
|
}
|
|
|
|
|
2015-09-03 22:48:12 +03:00
|
|
|
static size_t
|
|
|
|
iseqw_memsize(const void *ptr)
|
|
|
|
{
|
|
|
|
return iseq_memsize((const rb_iseq_t *)ptr);
|
|
|
|
}
|
|
|
|
|
2015-08-12 15:18:51 +03:00
|
|
|
static const rb_data_type_t iseqw_data_type = {
|
|
|
|
"T_IMEMO/iseq",
|
2015-09-03 22:48:12 +03:00
|
|
|
{iseqw_mark, NULL, iseqw_memsize,},
|
2015-08-12 15:18:51 +03:00
|
|
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
|
|
|
|
};
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
static VALUE
|
|
|
|
iseqw_new(const rb_iseq_t *iseq)
|
|
|
|
{
|
2018-12-06 13:52:27 +03:00
|
|
|
if (iseq->wrapper) {
|
|
|
|
return iseq->wrapper;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
union { const rb_iseq_t *in; void *out; } deconst;
|
|
|
|
VALUE obj;
|
|
|
|
deconst.in = iseq;
|
|
|
|
obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out);
|
|
|
|
RB_OBJ_WRITTEN(obj, Qundef, iseq);
|
2015-08-12 15:18:51 +03:00
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
/* cache a wrapper object */
|
|
|
|
RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj);
|
|
|
|
RB_OBJ_FREEZE((VALUE)iseq);
|
2015-08-12 15:18:51 +03:00
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
return obj;
|
|
|
|
}
|
2015-07-22 01:52:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_iseqw_new(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return iseqw_new(iseq);
|
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
|
|
|
|
* InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
|
|
|
|
*
|
|
|
|
* Takes +source+, a String of Ruby code and compiles it to an
|
|
|
|
* InstructionSequence.
|
|
|
|
*
|
|
|
|
* Optionally takes +file+, +path+, and +line+ which describe the filename,
|
|
|
|
* absolute path and first line number of the ruby code in +source+ which are
|
|
|
|
* metadata attached to the returned +iseq+.
|
|
|
|
*
|
|
|
|
* +options+, which can be +true+, +false+ or a +Hash+, is used to
|
2012-12-29 11:44:54 +04:00
|
|
|
* modify the default behavior of the Ruby iseq compiler.
|
|
|
|
*
|
|
|
|
* For details regarding valid compile options see ::compile_option=.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* RubyVM::InstructionSequence.compile("a = 1 + 2")
|
|
|
|
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
|
|
|
|
*
|
|
|
|
*/
|
* 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
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_s_compile(int argc, VALUE *argv, 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
|
|
|
{
|
2010-03-16 20:40:00 +03:00
|
|
|
VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
|
2016-09-27 09:23:36 +03:00
|
|
|
int i;
|
|
|
|
|
2007-12-25 12:43:23 +03:00
|
|
|
rb_secure(1);
|
|
|
|
|
2016-09-27 09:23:36 +03:00
|
|
|
i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
|
|
|
|
if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
|
|
|
|
switch (i) {
|
|
|
|
case 5: opt = argv[--i];
|
|
|
|
case 4: line = argv[--i];
|
|
|
|
case 3: path = argv[--i];
|
|
|
|
case 2: file = argv[--i];
|
|
|
|
}
|
2018-10-04 18:22:53 +03:00
|
|
|
|
2018-10-13 12:59:22 +03:00
|
|
|
if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
|
2018-10-04 18:22:53 +03:00
|
|
|
if (NIL_P(path)) path = file;
|
2009-03-10 04:54:01 +03:00
|
|
|
if (NIL_P(line)) line = INT2FIX(1);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-10-04 18:22:53 +03:00
|
|
|
Check_Type(path, T_STRING);
|
|
|
|
Check_Type(file, T_STRING);
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, 0, opt));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* InstructionSequence.compile_file(file[, options]) -> iseq
|
|
|
|
*
|
|
|
|
* Takes +file+, a String with the location of a Ruby source file, reads,
|
|
|
|
* parses and compiles the file, and returns +iseq+, the compiled
|
|
|
|
* InstructionSequence with source location metadata set.
|
|
|
|
*
|
|
|
|
* Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
|
2012-12-29 11:44:54 +04:00
|
|
|
* modify the default behavior of the Ruby iseq compiler.
|
|
|
|
*
|
|
|
|
* For details regarding valid compile options see ::compile_option=.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* # /tmp/hello.rb
|
|
|
|
* puts "Hello, world!"
|
|
|
|
*
|
|
|
|
* # elsewhere
|
|
|
|
* RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
|
|
|
|
* #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
|
|
|
|
*/
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
VALUE file, line = INT2FIX(1), opt = Qnil;
|
2017-10-27 19:44:57 +03:00
|
|
|
VALUE parser, f, exc = Qnil, ret;
|
2017-10-29 18:51:23 +03:00
|
|
|
rb_ast_t *ast;
|
* 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
|
|
|
rb_compile_option_t option;
|
2016-09-27 09:23:36 +03:00
|
|
|
int i;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-12-25 12:43:23 +03:00
|
|
|
rb_secure(1);
|
2016-09-27 09:23:36 +03:00
|
|
|
i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
|
|
|
|
if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
|
|
|
|
switch (i) {
|
|
|
|
case 2: opt = argv[--i];
|
|
|
|
}
|
2008-09-12 22:32:19 +04:00
|
|
|
FilePathValue(file);
|
2016-01-26 09:23:47 +03:00
|
|
|
file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2008-09-12 22:32:19 +04:00
|
|
|
f = rb_file_open_str(file, "r");
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
parser = rb_parser_new();
|
2016-09-27 11:35:31 +03:00
|
|
|
rb_parser_set_context(parser, NULL, FALSE);
|
2017-10-27 19:44:57 +03:00
|
|
|
ast = rb_parser_compile_file_path(parser, file, f, NUM2INT(line));
|
2018-01-05 11:59:20 +03:00
|
|
|
if (!ast->body.root) exc = GET_EC()->errinfo;
|
2014-11-26 05:03:06 +03:00
|
|
|
|
|
|
|
rb_io_close(f);
|
2018-01-05 11:59:20 +03:00
|
|
|
if (!ast->body.root) {
|
2017-10-27 19:44:57 +03:00
|
|
|
rb_ast_dispose(ast);
|
|
|
|
rb_exc_raise(exc);
|
|
|
|
}
|
2014-11-26 05:03:06 +03:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
make_compile_option(&option, opt);
|
2015-07-22 01:52:59 +03:00
|
|
|
|
2018-10-13 12:59:22 +03:00
|
|
|
ret = iseqw_new(rb_iseq_new_with_opt(&ast->body, rb_fstring_lit("<main>"),
|
2017-10-27 19:44:57 +03:00
|
|
|
file,
|
|
|
|
rb_realpath_internal(Qnil, file, 1),
|
|
|
|
line, NULL, ISEQ_TYPE_TOP, &option));
|
|
|
|
rb_ast_dispose(ast);
|
|
|
|
return ret;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* InstructionSequence.compile_option = options
|
|
|
|
*
|
|
|
|
* Sets the default values for various optimizations in the Ruby iseq
|
2012-12-29 11:44:54 +04:00
|
|
|
* compiler.
|
|
|
|
*
|
|
|
|
* Possible values for +options+ include +true+, which enables all options,
|
|
|
|
* +false+ which disables all options, and +nil+ which leaves all options
|
|
|
|
* unchanged.
|
|
|
|
*
|
|
|
|
* You can also pass a +Hash+ of +options+ that you want to change, any
|
|
|
|
* options not present in the hash will be left unchanged.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* Possible option names (which are keys in +options+) which can be set to
|
|
|
|
* +true+ or +false+ include:
|
|
|
|
*
|
|
|
|
* * +:inline_const_cache+
|
|
|
|
* * +:instructions_unification+
|
|
|
|
* * +:operands_unification+
|
|
|
|
* * +:peephole_optimization+
|
|
|
|
* * +:specialized_instruction+
|
|
|
|
* * +:stack_caching+
|
|
|
|
* * +:tailcall_optimization+
|
|
|
|
*
|
|
|
|
* Additionally, +:debug_level+ can be set to an integer.
|
|
|
|
*
|
|
|
|
* These default options can be overwritten for a single run of the iseq
|
|
|
|
* compiler by passing any of the above values as the +options+ parameter to
|
2012-12-29 11:44:54 +04:00
|
|
|
* ::new, ::compile and ::compile_file.
|
2012-07-25 01:29:24 +04:00
|
|
|
*/
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_s_compile_option_set(VALUE self, VALUE opt)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
* 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
|
|
|
rb_compile_option_t option;
|
2007-12-25 12:43:23 +03:00
|
|
|
rb_secure(1);
|
2006-12-31 18:02:22 +03:00
|
|
|
make_compile_option(&option, opt);
|
|
|
|
COMPILE_OPTION_DEFAULT = option;
|
2007-08-06 08:34:11 +04:00
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* InstructionSequence.compile_option -> options
|
|
|
|
*
|
|
|
|
* Returns a hash of default options used by the Ruby iseq compiler.
|
2012-12-29 11:44:54 +04:00
|
|
|
*
|
2012-07-25 01:29:24 +04:00
|
|
|
* For details, see InstructionSequence.compile_option=.
|
|
|
|
*/
|
2007-08-06 08:34:11 +04:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_s_compile_option_get(VALUE self)
|
2007-08-06 08:34:11 +04:00
|
|
|
{
|
|
|
|
return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
static const rb_iseq_t *
|
|
|
|
iseqw_check(VALUE iseqw)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-12-08 16:58:50 +03:00
|
|
|
rb_iseq_t *iseq = DATA_PTR(iseqw);
|
|
|
|
|
|
|
|
if (!iseq->body) {
|
2018-09-13 16:59:25 +03:00
|
|
|
rb_ibf_load_iseq_complete(iseq);
|
2015-12-08 16:58:50 +03:00
|
|
|
}
|
2015-07-22 01:52:59 +03:00
|
|
|
|
|
|
|
if (!iseq->body->location.label) {
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
|
|
|
|
}
|
|
|
|
return iseq;
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *
|
|
|
|
rb_iseqw_to_iseq(VALUE iseqw)
|
|
|
|
{
|
|
|
|
return iseqw_check(iseqw);
|
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* iseq.eval -> obj
|
|
|
|
*
|
|
|
|
* Evaluates the instruction sequence and returns the result.
|
|
|
|
*
|
|
|
|
* RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
|
|
|
|
*/
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_eval(VALUE self)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2007-12-25 12:43:23 +03:00
|
|
|
rb_secure(1);
|
2015-07-22 01:52:59 +03:00
|
|
|
return rb_iseq_eval(iseqw_check(self));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
2012-12-29 10:29:47 +04:00
|
|
|
* Returns a human-readable string representation of this instruction
|
|
|
|
* sequence, including the #label and #path.
|
2012-07-25 01:29:24 +04:00
|
|
|
*/
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_inspect(VALUE self)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *iseq = iseqw_check(self);
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2017-06-12 07:35:53 +03:00
|
|
|
VALUE klass = rb_class_name(rb_obj_class(self));
|
2015-07-22 01:52:59 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
if (!body->location.label) {
|
2017-06-12 07:35:53 +03:00
|
|
|
return rb_sprintf("#<%"PRIsVALUE": uninitialized>", klass);
|
2008-08-21 21:25:43 +04:00
|
|
|
}
|
2015-07-22 01:52:59 +03:00
|
|
|
else {
|
2017-12-23 12:10:34 +03:00
|
|
|
return rb_sprintf("<%"PRIsVALUE":%"PRIsVALUE"@%"PRIsVALUE":%d>",
|
2017-06-12 07:35:53 +03:00
|
|
|
klass,
|
2018-05-12 04:24:18 +03:00
|
|
|
body->location.label, rb_iseq_path(iseq),
|
2017-12-23 12:10:34 +03:00
|
|
|
FIX2INT(rb_iseq_first_lineno(iseq)));
|
2015-07-22 01:52:59 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2012-12-29 10:29:47 +04:00
|
|
|
/*
|
|
|
|
* Returns the path of this instruction sequence.
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* <code><compiled></code> if the iseq was evaluated from a string.
|
|
|
|
*
|
2012-12-29 10:29:47 +04:00
|
|
|
* For example, using irb:
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq.path
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> "<compiled>"
|
|
|
|
*
|
|
|
|
* Using ::compile_file:
|
|
|
|
*
|
|
|
|
* # /tmp/method.rb
|
|
|
|
* def hello
|
|
|
|
* puts "hello, world"
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* # in irb
|
2012-12-29 11:44:54 +04:00
|
|
|
* > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
|
|
|
|
* > iseq.path #=> /tmp/method.rb
|
2012-12-29 10:29:47 +04:00
|
|
|
*/
|
2015-07-22 01:52:59 +03:00
|
|
|
static VALUE
|
|
|
|
iseqw_path(VALUE self)
|
2012-11-30 22:02:43 +04:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
return rb_iseq_path(iseqw_check(self));
|
2012-11-30 22:02:43 +04:00
|
|
|
}
|
|
|
|
|
2012-12-29 10:29:47 +04:00
|
|
|
/*
|
|
|
|
* Returns the absolute path of this instruction sequence.
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* +nil+ if the iseq was evaluated from a string.
|
|
|
|
*
|
2012-12-29 10:29:47 +04:00
|
|
|
* For example, using ::compile_file:
|
|
|
|
*
|
|
|
|
* # /tmp/method.rb
|
|
|
|
* def hello
|
|
|
|
* puts "hello, world"
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* # in irb
|
2012-12-29 11:44:54 +04:00
|
|
|
* > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
|
|
|
|
* > iseq.absolute_path #=> /tmp/method.rb
|
2012-12-29 10:29:47 +04:00
|
|
|
*/
|
2015-07-22 01:52:59 +03:00
|
|
|
static VALUE
|
|
|
|
iseqw_absolute_path(VALUE self)
|
2012-11-30 22:02:43 +04:00
|
|
|
{
|
2017-06-01 03:05:33 +03:00
|
|
|
return rb_iseq_realpath(iseqw_check(self));
|
2012-11-30 22:02:43 +04:00
|
|
|
}
|
|
|
|
|
2012-12-29 10:29:47 +04:00
|
|
|
/* Returns the label of this instruction sequence.
|
2012-12-29 11:44:54 +04:00
|
|
|
*
|
|
|
|
* <code><main></code> if it's at the top level, <code><compiled></code> if it
|
|
|
|
* was evaluated from a string.
|
2012-12-29 10:29:47 +04:00
|
|
|
*
|
|
|
|
* For example, using irb:
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq.label
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> "<compiled>"
|
|
|
|
*
|
|
|
|
* Using ::compile_file:
|
|
|
|
*
|
|
|
|
* # /tmp/method.rb
|
|
|
|
* def hello
|
|
|
|
* puts "hello, world"
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* # in irb
|
2012-12-29 11:44:54 +04:00
|
|
|
* > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
|
|
|
|
* > iseq.label #=> <main>
|
2012-12-29 10:29:47 +04:00
|
|
|
*/
|
2015-12-08 18:07:41 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_label(VALUE self)
|
2012-11-30 22:02:43 +04:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
return rb_iseq_label(iseqw_check(self));
|
2012-11-30 22:02:43 +04:00
|
|
|
}
|
|
|
|
|
2012-12-29 10:29:47 +04:00
|
|
|
/* Returns the base label of this instruction sequence.
|
|
|
|
*
|
|
|
|
* For example, using irb:
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq.base_label
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> "<compiled>"
|
|
|
|
*
|
|
|
|
* Using ::compile_file:
|
|
|
|
*
|
|
|
|
* # /tmp/method.rb
|
|
|
|
* def hello
|
|
|
|
* puts "hello, world"
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* # in irb
|
2012-12-29 11:44:54 +04:00
|
|
|
* > iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
|
|
|
|
* > iseq.base_label #=> <main>
|
2012-12-29 10:29:47 +04:00
|
|
|
*/
|
2015-07-22 01:52:59 +03:00
|
|
|
static VALUE
|
|
|
|
iseqw_base_label(VALUE self)
|
2012-11-30 22:02:43 +04:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
return rb_iseq_base_label(iseqw_check(self));
|
2012-11-30 22:02:43 +04:00
|
|
|
}
|
|
|
|
|
2012-12-29 11:44:54 +04:00
|
|
|
/* Returns the number of the first source line where the instruction sequence
|
|
|
|
* was loaded from.
|
2012-12-29 10:29:47 +04:00
|
|
|
*
|
|
|
|
* For example, using irb:
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
|
2012-12-29 11:44:54 +04:00
|
|
|
* iseq.first_lineno
|
2012-12-29 10:29:47 +04:00
|
|
|
* #=> 1
|
|
|
|
*/
|
2015-12-08 18:07:41 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_first_lineno(VALUE self)
|
2012-11-30 22:02:43 +04:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
return rb_iseq_first_lineno(iseqw_check(self));
|
2013-10-08 16:08:20 +04:00
|
|
|
}
|
|
|
|
|
2015-07-22 00:28:43 +03:00
|
|
|
static VALUE iseq_data_to_ary(const rb_iseq_t *iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* iseq.to_a -> ary
|
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* Returns an Array with 14 elements representing the instruction sequence
|
|
|
|
* with the following data:
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* [magic]
|
2012-12-29 11:44:54 +04:00
|
|
|
* A string identifying the data format. <b>Always
|
|
|
|
* +YARVInstructionSequence/SimpleDataFormat+.</b>
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* [major_version]
|
|
|
|
* The major version of the instruction sequence.
|
|
|
|
*
|
|
|
|
* [minor_version]
|
|
|
|
* The minor version of the instruction sequence.
|
|
|
|
*
|
|
|
|
* [format_type]
|
2012-12-29 11:44:54 +04:00
|
|
|
* A number identifying the data format. <b>Always 1</b>.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* [misc]
|
2012-12-29 11:44:54 +04:00
|
|
|
* A hash containing:
|
|
|
|
*
|
|
|
|
* [+:arg_size+]
|
|
|
|
* the total number of arguments taken by the method or the block (0 if
|
|
|
|
* _iseq_ doesn't represent a method or block)
|
|
|
|
* [+:local_size+]
|
|
|
|
* the number of local variables + 1
|
|
|
|
* [+:stack_max+]
|
|
|
|
* used in calculating the stack depth at which a SystemStackError is
|
|
|
|
* thrown.
|
|
|
|
*
|
|
|
|
* [#label]
|
2012-07-25 01:29:24 +04:00
|
|
|
* The name of the context (block, method, class, module, etc.) that this
|
2012-12-29 11:44:54 +04:00
|
|
|
* instruction sequence belongs to.
|
|
|
|
*
|
|
|
|
* <code><main></code> if it's at the top level, <code><compiled></code> if
|
|
|
|
* it was evaluated from a string.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* [#path]
|
2012-07-25 01:29:24 +04:00
|
|
|
* The relative path to the Ruby file where the instruction sequence was
|
2012-12-29 11:44:54 +04:00
|
|
|
* loaded from.
|
|
|
|
*
|
|
|
|
* <code><compiled></code> if the iseq was evaluated from a string.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* [#absolute_path]
|
2012-07-25 01:29:24 +04:00
|
|
|
* The absolute path to the Ruby file where the instruction sequence was
|
2012-12-29 11:44:54 +04:00
|
|
|
* loaded from.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
2012-12-29 11:44:54 +04:00
|
|
|
* +nil+ if the iseq was evaluated from a string.
|
|
|
|
*
|
|
|
|
* [#first_lineno]
|
2012-07-25 01:29:24 +04:00
|
|
|
* The number of the first source line where the instruction sequence was
|
|
|
|
* loaded from.
|
|
|
|
*
|
|
|
|
* [type]
|
2012-12-29 11:44:54 +04:00
|
|
|
* The type of the instruction sequence.
|
|
|
|
*
|
|
|
|
* Valid values are +:top+, +:method+, +:block+, +:class+, +:rescue+,
|
2018-01-05 03:49:41 +03:00
|
|
|
* +:ensure+, +:eval+, +:main+, and +plain+.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* [locals]
|
|
|
|
* An array containing the names of all arguments and local variables as
|
|
|
|
* symbols.
|
|
|
|
*
|
2014-11-03 02:14:21 +03:00
|
|
|
* [params]
|
|
|
|
* An Hash object containing parameter information.
|
2012-07-25 01:29:24 +04:00
|
|
|
*
|
|
|
|
* More info about these values can be found in +vm_core.h+.
|
|
|
|
*
|
|
|
|
* [catch_table]
|
|
|
|
* A list of exceptions and control flow operators (rescue, next, redo,
|
|
|
|
* break, etc.).
|
|
|
|
*
|
|
|
|
* [bytecode]
|
|
|
|
* An array of arrays containing the instruction names and operands that
|
|
|
|
* make up the body of the instruction sequence.
|
|
|
|
*
|
2014-11-03 02:14:21 +03:00
|
|
|
* Note that this format is MRI specific and version dependent.
|
|
|
|
*
|
2012-07-25 01:29:24 +04:00
|
|
|
*/
|
2006-12-31 18:02:22 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_to_a(VALUE self)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *iseq = iseqw_check(self);
|
2007-12-25 12:43:23 +03:00
|
|
|
rb_secure(1);
|
2006-12-31 18:02:22 +03:00
|
|
|
return iseq_data_to_ary(iseq);
|
|
|
|
}
|
|
|
|
|
2018-01-01 16:18:55 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 1 /* binary search */
|
2017-12-20 10:38:24 +03:00
|
|
|
static const struct iseq_insn_info_entry *
|
|
|
|
get_insn_info_binary_search(const rb_iseq_t *iseq, size_t pos)
|
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
size_t size = body->insns_info.size;
|
|
|
|
const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
|
|
|
|
const unsigned int *positions = body->insns_info.positions;
|
2017-12-20 10:38:24 +03:00
|
|
|
const int debug = 0;
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
printf("size: %"PRIuSIZE"\n", size);
|
|
|
|
printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
|
2018-01-01 15:51:21 +03:00
|
|
|
(size_t)0, positions[0], insns_info[0].line_no, pos);
|
2017-12-20 10:38:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (size == 1) {
|
|
|
|
return &insns_info[0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
size_t l = 1, r = size - 1;
|
|
|
|
while (l <= r) {
|
|
|
|
size_t m = l + (r - l) / 2;
|
2018-01-01 15:51:21 +03:00
|
|
|
if (positions[m] == pos) {
|
2017-12-20 10:38:24 +03:00
|
|
|
return &insns_info[m];
|
|
|
|
}
|
2018-01-01 15:51:21 +03:00
|
|
|
if (positions[m] < pos) {
|
2017-12-20 10:38:24 +03:00
|
|
|
l = m + 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
r = m - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (l >= size) {
|
|
|
|
return &insns_info[size-1];
|
|
|
|
}
|
2018-01-01 15:51:21 +03:00
|
|
|
if (positions[l] > pos) {
|
2017-12-20 10:38:24 +03:00
|
|
|
return &insns_info[l-1];
|
|
|
|
}
|
|
|
|
return &insns_info[l];
|
|
|
|
}
|
|
|
|
}
|
2007-12-20 00:39:08 +03:00
|
|
|
|
2018-01-01 16:18:55 +03:00
|
|
|
static const struct iseq_insn_info_entry *
|
|
|
|
get_insn_info(const rb_iseq_t *iseq, size_t pos)
|
|
|
|
{
|
|
|
|
return get_insn_info_binary_search(iseq, pos);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-01-09 17:05:23 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2 /* succinct bitvector */
|
|
|
|
static const struct iseq_insn_info_entry *
|
|
|
|
get_insn_info_succinct_bitvector(const rb_iseq_t *iseq, size_t pos)
|
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
size_t size = body->insns_info.size;
|
|
|
|
const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
|
2018-01-09 17:05:23 +03:00
|
|
|
const int debug = 0;
|
|
|
|
|
|
|
|
if (debug) {
|
2018-05-19 06:43:00 +03:00
|
|
|
#if VM_CHECK_MODE > 0
|
|
|
|
const unsigned int *positions = body->insns_info.positions;
|
|
|
|
printf("size: %"PRIuSIZE"\n", size);
|
|
|
|
printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
|
|
|
|
(size_t)0, positions[0], insns_info[0].line_no, pos);
|
|
|
|
#else
|
|
|
|
printf("size: %"PRIuSIZE"\n", size);
|
|
|
|
printf("insns_info[%"PRIuSIZE"]: line: %d, pos: %"PRIuSIZE"\n",
|
|
|
|
(size_t)0, insns_info[0].line_no, pos);
|
|
|
|
#endif
|
2018-01-09 17:05:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (size == 1) {
|
|
|
|
return &insns_info[0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int index;
|
2018-05-12 04:24:18 +03:00
|
|
|
VM_ASSERT(body->insns_info.succ_index_table != NULL);
|
|
|
|
index = succ_index_lookup(body->insns_info.succ_index_table, (int)pos);
|
2018-01-09 17:05:23 +03:00
|
|
|
return &insns_info[index-1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct iseq_insn_info_entry *
|
|
|
|
get_insn_info(const rb_iseq_t *iseq, size_t pos)
|
|
|
|
{
|
|
|
|
return get_insn_info_succinct_bitvector(iseq, pos);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-01-01 16:18:55 +03:00
|
|
|
#if VM_CHECK_MODE > 0 || VM_INSN_INFO_TABLE_IMPL == 0
|
2017-11-09 09:57:24 +03:00
|
|
|
static const struct iseq_insn_info_entry *
|
2017-12-20 10:38:24 +03:00
|
|
|
get_insn_info_linear_search(const rb_iseq_t *iseq, size_t pos)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
size_t i = 0, size = body->insns_info.size;
|
|
|
|
const struct iseq_insn_info_entry *insns_info = body->insns_info.body;
|
|
|
|
const unsigned int *positions = body->insns_info.positions;
|
2011-08-24 10:31:15 +04:00
|
|
|
const int debug = 0;
|
|
|
|
|
|
|
|
if (debug) {
|
2016-09-13 15:33:13 +03:00
|
|
|
printf("size: %"PRIuSIZE"\n", size);
|
2017-11-09 09:57:24 +03:00
|
|
|
printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
|
2018-01-01 15:51:21 +03:00
|
|
|
i, positions[i], insns_info[i].line_no, pos);
|
2011-08-24 10:31:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
2017-11-09 09:57:24 +03:00
|
|
|
return NULL;
|
2011-08-24 10:31:15 +04:00
|
|
|
}
|
|
|
|
else if (size == 1) {
|
2017-11-09 09:57:24 +03:00
|
|
|
return &insns_info[0];
|
2011-08-24 10:31:15 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i=1; i<size; i++) {
|
2017-11-09 09:57:24 +03:00
|
|
|
if (debug) printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
|
2018-01-01 15:51:21 +03:00
|
|
|
i, positions[i], insns_info[i].line_no, pos);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-01-01 15:51:21 +03:00
|
|
|
if (positions[i] == pos) {
|
2017-11-09 09:57:24 +03:00
|
|
|
return &insns_info[i];
|
2011-09-15 09:24:42 +04:00
|
|
|
}
|
2018-01-01 15:51:21 +03:00
|
|
|
if (positions[i] > pos) {
|
2017-11-09 09:57:24 +03:00
|
|
|
return &insns_info[i-1];
|
2011-09-15 09:24:42 +04:00
|
|
|
}
|
2011-08-24 10:31:15 +04:00
|
|
|
}
|
|
|
|
}
|
2017-11-09 09:57:24 +03:00
|
|
|
return &insns_info[i-1];
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2018-01-01 16:18:55 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 0 /* linear search */
|
|
|
|
static const struct iseq_insn_info_entry *
|
|
|
|
get_insn_info(const rb_iseq_t *iseq, size_t pos)
|
|
|
|
{
|
|
|
|
return get_insn_info_linear_search(iseq, pos);
|
|
|
|
}
|
|
|
|
#endif
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-01-01 16:18:55 +03:00
|
|
|
#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
|
2017-12-20 10:38:24 +03:00
|
|
|
static void
|
2018-03-21 05:20:37 +03:00
|
|
|
validate_get_insn_info(const rb_iseq_t *iseq)
|
2017-12-20 10:38:24 +03:00
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2017-12-20 10:38:24 +03:00
|
|
|
size_t i;
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i = 0; i < body->iseq_size; i++) {
|
2018-01-01 16:18:55 +03:00
|
|
|
if (get_insn_info_linear_search(iseq, i) != get_insn_info(iseq, i)) {
|
|
|
|
rb_bug("validate_get_insn_info: get_insn_info_linear_search(iseq, %"PRIuSIZE") != get_insn_info(iseq, %"PRIuSIZE")", i, i);
|
2017-12-20 10:38:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-11-10 08:26:52 +03:00
|
|
|
unsigned int
|
|
|
|
rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
|
2007-12-20 00:39:08 +03:00
|
|
|
{
|
2018-01-01 16:18:55 +03:00
|
|
|
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
|
2015-07-25 00:01:09 +03:00
|
|
|
|
2007-12-20 00:39:08 +03:00
|
|
|
if (entry) {
|
|
|
|
return entry->line_no;
|
|
|
|
}
|
2007-12-20 10:44:03 +03:00
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
2007-12-20 00:39:08 +03:00
|
|
|
}
|
|
|
|
|
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
|
|
|
MJIT_FUNC_EXPORTED rb_event_flag_t
|
2017-11-14 15:58:36 +03:00
|
|
|
rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
|
|
|
|
{
|
2018-01-01 16:18:55 +03:00
|
|
|
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
|
2017-11-14 15:58:36 +03:00
|
|
|
if (entry) {
|
|
|
|
return entry->events;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-20 08:33:04 +03:00
|
|
|
void
|
|
|
|
rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset)
|
|
|
|
{
|
|
|
|
struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos);
|
|
|
|
if (entry) {
|
2018-10-20 08:33:13 +03:00
|
|
|
entry->events &= ~reset;
|
2018-12-06 13:52:27 +03:00
|
|
|
if (!(entry->events & iseq->aux.exec.global_trace_events)) {
|
2018-10-20 08:44:12 +03:00
|
|
|
void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos);
|
2018-10-20 08:33:04 +03:00
|
|
|
rb_iseq_trace_flag_cleared(iseq, pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 02:08:01 +03:00
|
|
|
static VALUE
|
|
|
|
local_var_name(const rb_iseq_t *diseq, VALUE level, VALUE op)
|
|
|
|
{
|
|
|
|
VALUE i;
|
2018-01-30 05:08:30 +03:00
|
|
|
VALUE name;
|
2017-11-10 02:08:01 +03:00
|
|
|
ID lid;
|
2018-03-19 03:32:52 +03:00
|
|
|
int idx;
|
2017-11-10 02:08:01 +03:00
|
|
|
|
|
|
|
for (i = 0; i < level; i++) {
|
|
|
|
diseq = diseq->body->parent_iseq;
|
|
|
|
}
|
2018-03-19 03:32:52 +03:00
|
|
|
idx = diseq->body->local_table_size - (int)op - 1;
|
|
|
|
lid = diseq->body->local_table[idx];
|
2018-01-30 05:08:30 +03:00
|
|
|
name = rb_id2str(lid);
|
|
|
|
if (!name) {
|
2018-03-19 03:32:52 +03:00
|
|
|
name = rb_str_new_cstr("?");
|
2018-01-30 05:08:30 +03:00
|
|
|
}
|
|
|
|
else if (!rb_str_symname_p(name)) {
|
|
|
|
name = rb_str_inspect(name);
|
|
|
|
}
|
2018-03-19 03:32:52 +03:00
|
|
|
else {
|
|
|
|
name = rb_str_dup(name);
|
|
|
|
}
|
|
|
|
rb_str_catf(name, "@%d", idx);
|
2018-01-30 05:08:30 +03:00
|
|
|
return name;
|
2017-11-10 02:08:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int rb_insn_unified_local_var_level(VALUE);
|
|
|
|
|
2012-10-04 16:31:05 +04:00
|
|
|
VALUE
|
2014-06-18 10:16:39 +04:00
|
|
|
rb_insn_operand_intern(const rb_iseq_t *iseq,
|
2013-03-06 10:30:03 +04:00
|
|
|
VALUE insn, int op_no, VALUE op,
|
2014-06-18 10:16:39 +04:00
|
|
|
int len, size_t pos, const VALUE *pnop, VALUE child)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2008-04-03 04:00:48 +04:00
|
|
|
const char *types = insn_op_types(insn);
|
2006-12-31 18:02:22 +03:00
|
|
|
char type = types[op_no];
|
2015-12-08 16:58:50 +03:00
|
|
|
VALUE ret = Qundef;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
switch (type) {
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_OFFSET: /* LONG */
|
2010-10-15 18:11:26 +04:00
|
|
|
ret = rb_sprintf("%"PRIdVALUE, (VALUE)(pos + len + op));
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
|
|
|
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_NUM: /* ULONG */
|
2018-01-17 09:23:57 +03:00
|
|
|
if (insn == BIN(defined) && op_no == 0) {
|
|
|
|
enum defined_type deftype = (enum defined_type)op;
|
|
|
|
if (deftype == DEFINED_FUNC) {
|
2018-10-13 12:59:22 +03:00
|
|
|
ret = rb_fstring_lit("func"); break;
|
iseq.c: dump type of branchiftype on disasm
This makes easier to debug scripts related to r59950.
* before
$ ./ruby --dump=insns -e '"#{a}"'
== disasm: #<ISeq:<main>@-e>============================================
0000 putobject "" ( 1)[Li]
0002 putself
0003 opt_send_without_block <callinfo!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache>
0006 dup
0007 branchiftype 5, 15
0010 dup
0011 opt_send_without_block <callinfo!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>, <callcache>
0014 tostring
0015 concatstrings 2
0017 leave
* after
$ ./ruby --dump=insns -e '"#{a}"'
== disasm: #<ISeq:<main>@-e>============================================
0000 putobject "" ( 1)[Li]
0002 putself
0003 opt_send_without_block <callinfo!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache>
0006 dup
0007 branchiftype T_STRING, 15
0010 dup
0011 opt_send_without_block <callinfo!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>, <callcache>
0014 tostring
0015 concatstrings 2
0017 leave
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61217 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-12-13 19:07:52 +03:00
|
|
|
}
|
2018-01-17 09:23:57 +03:00
|
|
|
if (deftype == DEFINED_REF) {
|
2018-10-13 12:59:22 +03:00
|
|
|
ret = rb_fstring_lit("ref"); break;
|
2017-12-22 03:29:38 +03:00
|
|
|
}
|
2018-01-18 15:54:24 +03:00
|
|
|
ret = rb_iseq_defined_string(deftype);
|
2018-01-17 09:23:57 +03:00
|
|
|
if (ret) break;
|
|
|
|
}
|
2018-04-21 13:52:52 +03:00
|
|
|
else if (insn == BIN(checktype) && op_no == 0) {
|
2018-01-17 09:23:57 +03:00
|
|
|
const char *type_str = rb_type_str((enum ruby_value_type)op);
|
|
|
|
if (type_str) {
|
|
|
|
ret = rb_str_new_cstr(type_str); break;
|
iseq.c: dump type of branchiftype on disasm
This makes easier to debug scripts related to r59950.
* before
$ ./ruby --dump=insns -e '"#{a}"'
== disasm: #<ISeq:<main>@-e>============================================
0000 putobject "" ( 1)[Li]
0002 putself
0003 opt_send_without_block <callinfo!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache>
0006 dup
0007 branchiftype 5, 15
0010 dup
0011 opt_send_without_block <callinfo!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>, <callcache>
0014 tostring
0015 concatstrings 2
0017 leave
* after
$ ./ruby --dump=insns -e '"#{a}"'
== disasm: #<ISeq:<main>@-e>============================================
0000 putobject "" ( 1)[Li]
0002 putself
0003 opt_send_without_block <callinfo!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache>
0006 dup
0007 branchiftype T_STRING, 15
0010 dup
0011 opt_send_without_block <callinfo!mid:to_s, argc:0, FCALL|ARGS_SIMPLE>, <callcache>
0014 tostring
0015 concatstrings 2
0017 leave
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61217 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-12-13 19:07:52 +03:00
|
|
|
}
|
|
|
|
}
|
2018-01-17 09:23:57 +03:00
|
|
|
ret = rb_sprintf("%"PRIuVALUE, op);
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
|
|
|
|
2012-10-04 17:52:20 +04:00
|
|
|
case TS_LINDEX:{
|
2017-11-10 02:08:01 +03:00
|
|
|
int level;
|
2017-12-23 03:55:29 +03:00
|
|
|
if (types[op_no+1] == TS_NUM && pnop) {
|
2018-01-30 05:08:30 +03:00
|
|
|
ret = local_var_name(iseq, *pnop, op - VM_ENV_DATA_SIZE);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2017-11-10 02:08:01 +03:00
|
|
|
else if ((level = rb_insn_unified_local_var_level(insn)) >= 0) {
|
2018-01-30 05:08:30 +03:00
|
|
|
ret = local_var_name(iseq, (VALUE)level, op - VM_ENV_DATA_SIZE);
|
2017-11-10 02:08:01 +03:00
|
|
|
}
|
2007-05-11 10:26:06 +04:00
|
|
|
else {
|
|
|
|
ret = rb_inspect(INT2FIX(op));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TS_ID: /* ID (symbol) */
|
2017-12-22 03:29:38 +03:00
|
|
|
ret = rb_inspect(ID2SYM(op));
|
|
|
|
break;
|
2008-05-14 07:48:39 +04:00
|
|
|
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_VALUE: /* VALUE */
|
2009-02-18 08:33:36 +03:00
|
|
|
op = obj_resurrect(op);
|
2017-12-22 03:29:38 +03:00
|
|
|
if (insn == BIN(defined) && op_no == 1 && FIXNUM_P(op)) {
|
|
|
|
/* should be DEFINED_REF */
|
|
|
|
int type = NUM2INT(op);
|
|
|
|
if (type) {
|
|
|
|
if (type & 1) {
|
|
|
|
ret = rb_sprintf(":$%c", (type >> 1));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret = rb_sprintf(":$%d", (type >> 1));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-05-14 07:48:39 +04:00
|
|
|
ret = rb_inspect(op);
|
|
|
|
if (CLASS_OF(op) == rb_cISeq) {
|
2012-10-04 16:31:05 +04:00
|
|
|
if (child) {
|
|
|
|
rb_ary_push(child, op);
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_ISEQ: /* iseq */
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-12-08 16:58:50 +03:00
|
|
|
if (op) {
|
|
|
|
const rb_iseq_t *iseq = rb_iseq_check((rb_iseq_t *)op);
|
2015-07-22 01:52:59 +03:00
|
|
|
ret = iseq->body->location.label;
|
2006-12-31 18:02:22 +03:00
|
|
|
if (child) {
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_ary_push(child, (VALUE)iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret = rb_str_new2("nil");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_GENTRY:
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2009-07-16 04:01:06 +04:00
|
|
|
struct rb_global_entry *entry = (struct rb_global_entry *)op;
|
2007-12-24 19:38:44 +03:00
|
|
|
ret = rb_str_dup(rb_id2str(entry->id));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_IC:
|
2018-03-19 21:21:54 +03:00
|
|
|
case TS_ISE:
|
2015-07-22 01:52:59 +03:00
|
|
|
ret = rb_sprintf("<is:%"PRIdPTRDIFF">", (union iseq_inline_storage_entry *)op - iseq->body->is_entries);
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
|
|
|
|
2012-10-10 21:52:24 +04:00
|
|
|
case TS_CALLINFO:
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
{
|
2015-09-19 20:59:58 +03:00
|
|
|
struct rb_call_info *ci = (struct rb_call_info *)op;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
VALUE ary = rb_ary_new();
|
|
|
|
|
|
|
|
if (ci->mid) {
|
2014-11-23 20:03:32 +03:00
|
|
|
rb_ary_push(ary, rb_sprintf("mid:%"PRIsVALUE, rb_id2str(ci->mid)));
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
rb_ary_push(ary, rb_sprintf("argc:%d", ci->orig_argc));
|
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
if (ci->flag & VM_CALL_KWARG) {
|
2015-10-14 08:11:44 +03:00
|
|
|
struct rb_call_info_kw_arg *kw_args = ((struct rb_call_info_with_kwarg *)ci)->kw_arg;
|
|
|
|
VALUE kw_ary = rb_ary_new_from_values(kw_args->keyword_len, kw_args->keywords);
|
|
|
|
rb_ary_push(ary, rb_sprintf("kw:[%"PRIsVALUE"]", rb_ary_join(kw_ary, rb_str_new2(","))));
|
* rewrite method/block parameter fitting logic to optimize
keyword arguments/parameters and a splat argument.
[Feature #10440] (Details are described in this ticket)
Most of complex part is moved to vm_args.c.
Now, ISeq#to_a does not catch up new instruction format.
* vm_core.h: change iseq data structures.
* introduce rb_call_info_kw_arg_t to represent keyword arguments.
* add rb_call_info_t::kw_arg.
* rename rb_iseq_t::arg_post_len to rb_iseq_t::arg_post_num.
* rename rb_iseq_t::arg_keywords to arg_keyword_num.
* rename rb_iseq_t::arg_keyword to rb_iseq_t::arg_keyword_bits.
to represent keyword bitmap parameter index.
This bitmap parameter shows that which keyword parameters are given
or not given (0 for given).
It is refered by `checkkeyword' instruction described bellow.
* rename rb_iseq_t::arg_keyword_check to rb_iseq_t::arg_keyword_rest
to represent keyword rest parameter index.
* add rb_iseq_t::arg_keyword_default_values to represent default
keyword values.
* rename VM_CALL_ARGS_SKIP_SETUP to VM_CALL_ARGS_SIMPLE
to represent
(ci->flag & (SPLAT|BLOCKARG)) &&
ci->blockiseq == NULL &&
ci->kw_arg == NULL.
* vm_insnhelper.c, vm_args.c: rewrite with refactoring.
* rewrite splat argument code.
* rewrite keyword arguments/parameters code.
* merge method and block parameter fitting code into one code base.
* vm.c, vm_eval.c: catch up these changes.
* compile.c (new_callinfo): callinfo requires kw_arg parameter.
* compile.c (compile_array_): check the last argument Hash object or
not. If Hash object and all keys are Symbol literals, they are
compiled to keyword arguments.
* insns.def (checkkeyword): add new instruction.
This instruction check the availability of corresponding keyword.
For example, a method "def foo k1: 'v1'; end" is cimpiled to the
following instructions.
0000 checkkeyword 2, 0 # check k1 is given.
0003 branchif 9 # if given, jump to address #9
0005 putstring "v1"
0007 setlocal_OP__WC__0 3 # k1 = 'v1'
0009 trace 8
0011 putnil
0012 trace 16
0014 leave
* insns.def (opt_send_simple): removed and add new instruction
"opt_send_without_block".
* parse.y (new_args_tail_gen): reorder variables.
Before this patch, a method "def foo(k1: 1, kr1:, k2: 2, **krest, &b)"
has parameter variables "k1, kr1, k2, &b, internal_id, krest",
but this patch reorders to "kr1, k1, k2, internal_id, krest, &b".
(locate a block variable at last)
* parse.y (vtable_pop): added.
This function remove latest `n' variables from vtable.
* iseq.c: catch up iseq data changes.
* proc.c: ditto.
* class.c (keyword_error): export as rb_keyword_error().
* common.mk: depend vm_args.c for vm.o.
* hash.c (rb_hash_has_key): export.
* internal.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48239 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-11-02 21:02:55 +03:00
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
|
|
|
|
if (ci->flag) {
|
|
|
|
VALUE flags = rb_ary_new();
|
2017-12-22 03:29:38 +03:00
|
|
|
# define CALL_FLAG(n) if (ci->flag & VM_CALL_##n) rb_ary_push(flags, rb_str_new2(#n))
|
|
|
|
CALL_FLAG(ARGS_SPLAT);
|
|
|
|
CALL_FLAG(ARGS_BLOCKARG);
|
|
|
|
CALL_FLAG(FCALL);
|
|
|
|
CALL_FLAG(VCALL);
|
|
|
|
CALL_FLAG(ARGS_SIMPLE);
|
|
|
|
CALL_FLAG(BLOCKISEQ);
|
|
|
|
CALL_FLAG(TAILCALL);
|
|
|
|
CALL_FLAG(SUPER);
|
2018-08-10 10:45:16 +03:00
|
|
|
CALL_FLAG(ZSUPER);
|
2017-12-22 03:29:38 +03:00
|
|
|
CALL_FLAG(KWARG);
|
|
|
|
CALL_FLAG(KW_SPLAT);
|
|
|
|
CALL_FLAG(OPT_SEND); /* maybe not reachable */
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
|
|
|
|
}
|
|
|
|
ret = rb_sprintf("<callinfo!%"PRIsVALUE">", rb_ary_join(ary, rb_str_new2(", ")));
|
|
|
|
}
|
2012-10-10 21:52:24 +04:00
|
|
|
break;
|
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
case TS_CALLCACHE:
|
|
|
|
ret = rb_str_new2("<callcache>");
|
|
|
|
break;
|
|
|
|
|
2007-05-11 10:26:06 +04:00
|
|
|
case TS_CDHASH:
|
2006-12-31 18:02:22 +03:00
|
|
|
ret = rb_str_new2("<cdhash>");
|
|
|
|
break;
|
|
|
|
|
2007-08-12 23:09:15 +04:00
|
|
|
case TS_FUNCPTR:
|
2014-12-16 04:14:27 +03:00
|
|
|
{
|
|
|
|
#ifdef HAVE_DLADDR
|
|
|
|
Dl_info info;
|
|
|
|
if (dladdr((void *)op, &info) && info.dli_sname) {
|
|
|
|
ret = rb_str_new_cstr(info.dli_sname);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ret = rb_str_new2("<funcptr>");
|
|
|
|
}
|
2007-08-12 23:09:15 +04:00
|
|
|
break;
|
|
|
|
|
2007-05-11 10:26:06 +04:00
|
|
|
default:
|
2018-04-27 16:14:09 +03:00
|
|
|
rb_bug("unknown operand type: %c", type);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-04-04 07:28:47 +03:00
|
|
|
static VALUE
|
|
|
|
right_strip(VALUE str)
|
|
|
|
{
|
|
|
|
const char *beg = RSTRING_PTR(str), *end = RSTRING_END(str);
|
|
|
|
while (end-- > beg && *end == ' ');
|
|
|
|
rb_str_set_len(str, end - beg + 1);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
/**
|
|
|
|
* Disassemble a instruction
|
|
|
|
* Iseq -> Iseq inspect object
|
|
|
|
*/
|
* compile.c, cont.c, gc.c, insns.def, iseq.c, iseq.h, process.c,
thread.c, vm.c, vm_core.h, vm_dump.c, vm_eval.c,
vm_insnhelper.c, vm_method.c, template/insns_info.inc.tmpl,
tool/instruction.rb: fixed types.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25030 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-09-22 00:58:26 +04:00
|
|
|
int
|
2015-07-16 15:50:25 +03:00
|
|
|
rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
|
|
|
|
const rb_iseq_t *iseq, VALUE child)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-16 15:50:25 +03:00
|
|
|
VALUE insn = code[pos];
|
2006-12-31 18:02:22 +03:00
|
|
|
int len = insn_len(insn);
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
int j;
|
2008-04-03 04:00:48 +04:00
|
|
|
const char *types = insn_op_types(insn);
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE str = rb_str_new(0, 0);
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
const char *insn_name_buff;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
insn_name_buff = insn_name(insn);
|
|
|
|
if (1) {
|
2018-05-02 03:57:50 +03:00
|
|
|
extern const int rb_vm_max_insn_name_size;
|
|
|
|
rb_str_catf(str, "%04"PRIuSIZE" %-*s ", pos, rb_vm_max_insn_name_size, insn_name_buff);
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
}
|
|
|
|
else {
|
2018-05-02 03:57:47 +03:00
|
|
|
rb_str_catf(str, "%04"PRIuSIZE" %-28.*s ", pos,
|
2008-07-31 05:51:44 +04:00
|
|
|
(int)strcspn(insn_name_buff, "_"), insn_name_buff);
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
for (j = 0; types[j]; j++) {
|
2015-07-16 15:50:25 +03:00
|
|
|
VALUE opstr = rb_insn_operand_intern(iseq, insn, j, code[pos + j + 1],
|
|
|
|
len, pos, &code[pos + j + 2],
|
2013-03-06 10:30:03 +04:00
|
|
|
child);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_str_concat(str, opstr);
|
|
|
|
|
|
|
|
if (types[j + 1]) {
|
|
|
|
rb_str_cat2(str, ", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-24 10:31:15 +04:00
|
|
|
{
|
2017-11-10 08:26:52 +03:00
|
|
|
unsigned int line_no = rb_iseq_line_no(iseq, pos);
|
|
|
|
unsigned int prev = pos == 0 ? 0 : rb_iseq_line_no(iseq, pos - 1);
|
2006-12-31 18:02:22 +03:00
|
|
|
if (line_no && line_no != prev) {
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
long slen = RSTRING_LEN(str);
|
|
|
|
slen = (slen > 70) ? 0 : (70 - slen);
|
|
|
|
str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
2007-12-20 00:39:08 +03:00
|
|
|
|
2017-11-14 15:58:36 +03:00
|
|
|
{
|
|
|
|
rb_event_flag_t events = rb_iseq_event_flags(iseq, pos);
|
|
|
|
if (events) {
|
2018-10-20 13:45:55 +03:00
|
|
|
str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s]",
|
2017-11-14 15:58:36 +03:00
|
|
|
events & RUBY_EVENT_LINE ? "Li" : "",
|
|
|
|
events & RUBY_EVENT_CLASS ? "Cl" : "",
|
|
|
|
events & RUBY_EVENT_END ? "En" : "",
|
|
|
|
events & RUBY_EVENT_CALL ? "Ca" : "",
|
|
|
|
events & RUBY_EVENT_RETURN ? "Re" : "",
|
|
|
|
events & RUBY_EVENT_C_CALL ? "Cc" : "",
|
|
|
|
events & RUBY_EVENT_C_RETURN ? "Cr" : "",
|
|
|
|
events & RUBY_EVENT_B_CALL ? "Bc" : "",
|
2018-10-20 13:45:55 +03:00
|
|
|
events & RUBY_EVENT_B_RETURN ? "Br" : "",
|
|
|
|
events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
|
2018-11-26 21:16:39 +03:00
|
|
|
events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
|
2017-11-14 15:58:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 07:28:47 +03:00
|
|
|
right_strip(str);
|
2006-12-31 18:02:22 +03:00
|
|
|
if (ret) {
|
|
|
|
rb_str_cat2(str, "\n");
|
|
|
|
rb_str_concat(ret, str);
|
|
|
|
}
|
|
|
|
else {
|
2018-04-04 07:28:47 +03:00
|
|
|
printf("%.*s\n", (int)RSTRING_LEN(str), RSTRING_PTR(str));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2008-05-31 13:28:20 +04:00
|
|
|
static const char *
|
2006-12-31 18:02:22 +03:00
|
|
|
catch_type(int type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
2007-05-11 10:26:06 +04:00
|
|
|
case CATCH_TYPE_RESCUE:
|
2006-12-31 18:02:22 +03:00
|
|
|
return "rescue";
|
2007-05-11 10:26:06 +04:00
|
|
|
case CATCH_TYPE_ENSURE:
|
2006-12-31 18:02:22 +03:00
|
|
|
return "ensure";
|
2007-05-11 10:26:06 +04:00
|
|
|
case CATCH_TYPE_RETRY:
|
2006-12-31 18:02:22 +03:00
|
|
|
return "retry";
|
2007-05-11 10:26:06 +04:00
|
|
|
case CATCH_TYPE_BREAK:
|
2006-12-31 18:02:22 +03:00
|
|
|
return "break";
|
2007-05-11 10:26:06 +04:00
|
|
|
case CATCH_TYPE_REDO:
|
2006-12-31 18:02:22 +03:00
|
|
|
return "redo";
|
2007-05-11 10:26:06 +04:00
|
|
|
case CATCH_TYPE_NEXT:
|
2006-12-31 18:02:22 +03:00
|
|
|
return "next";
|
2007-05-11 10:26:06 +04:00
|
|
|
default:
|
2018-04-27 16:14:09 +03:00
|
|
|
rb_bug("unknown catch type: %d", type);
|
2006-12-31 18:02:22 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
static VALUE
|
|
|
|
iseq_inspect(const rb_iseq_t *iseq)
|
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
if (!body->location.label) {
|
2015-07-22 01:52:59 +03:00
|
|
|
return rb_sprintf("#<ISeq: uninitialized>");
|
|
|
|
}
|
|
|
|
else {
|
2018-05-12 04:24:18 +03:00
|
|
|
const rb_code_location_t *loc = &body->location.code_location;
|
2018-01-11 11:34:55 +03:00
|
|
|
return rb_sprintf("#<ISeq:%"PRIsVALUE"@%"PRIsVALUE":%d (%d,%d)-(%d,%d)>",
|
2018-05-12 04:24:18 +03:00
|
|
|
body->location.label, rb_iseq_path(iseq),
|
|
|
|
loc->beg_pos.lineno,
|
|
|
|
loc->beg_pos.lineno,
|
|
|
|
loc->beg_pos.column,
|
|
|
|
loc->end_pos.lineno,
|
|
|
|
loc->end_pos.column);
|
2015-07-22 01:52:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 14:00:39 +03:00
|
|
|
static VALUE
|
|
|
|
rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2015-07-16 15:50:25 +03:00
|
|
|
VALUE *code;
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE str = rb_str_new(0, 0);
|
2015-07-22 01:52:59 +03:00
|
|
|
VALUE child = rb_ary_tmp_new(3);
|
2014-07-26 11:30:26 +04:00
|
|
|
unsigned int size;
|
2015-07-25 00:44:14 +03:00
|
|
|
unsigned int i;
|
2009-03-11 23:19:24 +03:00
|
|
|
long l;
|
* compile.c, cont.c, gc.c, insns.def, iseq.c, iseq.h, process.c,
thread.c, vm.c, vm_core.h, vm_dump.c, vm_eval.c,
vm_insnhelper.c, vm_method.c, template/insns_info.inc.tmpl,
tool/instruction.rb: fixed types.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25030 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-09-22 00:58:26 +04:00
|
|
|
size_t n;
|
2007-08-06 08:34:11 +04:00
|
|
|
enum {header_minlen = 72};
|
2017-11-10 11:26:44 +03:00
|
|
|
st_table *done_iseq = 0;
|
2018-04-04 14:00:39 +03:00
|
|
|
const char *indent_str;
|
|
|
|
long indent_len;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-12-25 12:43:23 +03:00
|
|
|
rb_secure(1);
|
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
size = body->iseq_size;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-04-04 14:00:39 +03:00
|
|
|
indent_len = RSTRING_LEN(indent);
|
|
|
|
indent_str = RSTRING_PTR(indent);
|
|
|
|
|
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_str_cat2(str, "== disasm: ");
|
|
|
|
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_append(str, iseq_inspect(iseq));
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_str_catf(str, " (catch: %s)", body->catch_except_p ? "TRUE" : "FALSE");
|
2018-04-04 14:00:39 +03:00
|
|
|
if ((l = RSTRING_LEN(str) - indent_len) < header_minlen) {
|
|
|
|
rb_str_modify_expand(str, header_minlen - l);
|
|
|
|
memset(RSTRING_END(str), '=', header_minlen - l);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
rb_str_cat2(str, "\n");
|
|
|
|
|
|
|
|
/* show catch table information */
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->catch_table) {
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_str_cat2(str, "== catch table\n");
|
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->catch_table) {
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat_cstr(indent, "| ");
|
|
|
|
indent_str = RSTRING_PTR(indent);
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i = 0; i < body->catch_table->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
const struct iseq_catch_table_entry *entry =
|
|
|
|
UNALIGNED_MEMBER_PTR(body->catch_table, entries[i]);
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
2015-07-25 00:44:14 +03:00
|
|
|
rb_str_catf(str,
|
|
|
|
"| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
|
|
|
|
catch_type((int)entry->type), (int)entry->start,
|
|
|
|
(int)entry->end, (int)entry->sp, (int)entry->cont);
|
2017-11-10 11:26:44 +03:00
|
|
|
if (entry->iseq && !(done_iseq && st_is_member(done_iseq, (st_data_t)entry->iseq))) {
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_concat(str, rb_iseq_disasm_recursive(rb_iseq_check(entry->iseq), indent));
|
2017-11-10 11:26:44 +03:00
|
|
|
if (!done_iseq) done_iseq = st_init_numtable();
|
|
|
|
st_insert(done_iseq, (st_data_t)entry->iseq, (st_data_t)0);
|
2018-04-04 14:00:39 +03:00
|
|
|
indent_str = RSTRING_PTR(indent);
|
2015-07-25 00:44:14 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_resize(indent, indent_len);
|
|
|
|
indent_str = RSTRING_PTR(indent);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->catch_table) {
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_str_cat2(str, "|-------------------------------------"
|
|
|
|
"-----------------------------------\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* show local table information */
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->local_table) {
|
|
|
|
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
* compile.c (insn_data_to_s_detail), file.c (rb_stat_inspect),
iseq.c (ruby_iseq_disasm_insn, ruby_iseq_disasm),
process.c (pst_message), re.c (match_inspect): use rb_str_catf.
* dir.c (dir_inspect), iseq.c (iseq_inspect, insn_operand_intern): use
rb_sprintf.
* error.c (rb_name_error, rb_raise, rb_loaderror, rb_fatal): use
rb_vsprintf.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-07-22 12:53:34 +04:00
|
|
|
rb_str_catf(str,
|
|
|
|
"local table (size: %d, argc: %d "
|
2014-11-03 02:14:21 +03:00
|
|
|
"[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n",
|
2018-05-12 04:24:18 +03:00
|
|
|
body->local_table_size,
|
|
|
|
body->param.lead_num,
|
|
|
|
body->param.opt_num,
|
|
|
|
body->param.flags.has_rest ? body->param.rest_start : -1,
|
|
|
|
body->param.post_num,
|
|
|
|
body->param.flags.has_block ? body->param.block_start : -1,
|
|
|
|
body->param.flags.has_kw ? keyword->num : -1,
|
|
|
|
body->param.flags.has_kw ? keyword->required_num : -1,
|
|
|
|
body->param.flags.has_kwrest ? keyword->rest_start : -1);
|
|
|
|
|
|
|
|
for (i = body->local_table_size; i > 0;) {
|
|
|
|
int li = body->local_table_size - --i - 1;
|
2012-06-09 18:36:56 +04:00
|
|
|
long width;
|
2018-01-30 05:08:30 +03:00
|
|
|
VALUE name = local_var_name(iseq, 0, i);
|
2019-04-29 05:31:18 +03:00
|
|
|
char argi[0x100];
|
|
|
|
char opti[0x100];
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2019-04-29 05:31:18 +03:00
|
|
|
opti[0] = '\0';
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->param.flags.has_opt) {
|
|
|
|
int argc = body->param.lead_num;
|
|
|
|
int opts = body->param.opt_num;
|
2015-07-25 00:44:14 +03:00
|
|
|
if (li >= argc && li < argc + opts) {
|
2010-10-13 18:07:22 +04:00
|
|
|
snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
|
2018-05-12 04:24:18 +03:00
|
|
|
body->param.opt_table[li - argc]);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-19 03:32:51 +03:00
|
|
|
snprintf(argi, sizeof(argi), "%s%s%s%s%s%s", /* arg, opts, rest, post, kwrest, block */
|
2018-05-12 04:24:18 +03:00
|
|
|
body->param.lead_num > li ? "Arg" : "",
|
2006-12-31 18:02:22 +03:00
|
|
|
opti,
|
2018-05-12 04:24:18 +03:00
|
|
|
(body->param.flags.has_rest && body->param.rest_start == li) ? "Rest" : "",
|
|
|
|
(body->param.flags.has_post && body->param.post_start <= li && li < body->param.post_start + body->param.post_num) ? "Post" : "",
|
|
|
|
(body->param.flags.has_kwrest && keyword->rest_start == li) ? "Kwrest" : "",
|
|
|
|
(body->param.flags.has_block && body->param.block_start == li) ? "Block" : "");
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
2018-01-30 05:08:30 +03:00
|
|
|
rb_str_catf(str, "[%2d] ", i + 1);
|
2012-06-09 18:36:56 +04:00
|
|
|
width = RSTRING_LEN(str) + 11;
|
2018-01-30 05:08:30 +03:00
|
|
|
rb_str_append(str, name);
|
2012-06-09 18:36:56 +04:00
|
|
|
if (*argi) rb_str_catf(str, "<%s>", argi);
|
|
|
|
if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2018-04-04 07:28:47 +03:00
|
|
|
rb_str_cat_cstr(right_strip(str), "\n");
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* show each line */
|
2015-07-16 15:50:25 +03:00
|
|
|
code = rb_iseq_original_iseq(iseq);
|
* compile.c, cont.c, gc.c, insns.def, iseq.c, iseq.h, process.c,
thread.c, vm.c, vm_core.h, vm_dump.c, vm_eval.c,
vm_insnhelper.c, vm_method.c, template/insns_info.inc.tmpl,
tool/instruction.rb: fixed types.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25030 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-09-22 00:58:26 +04:00
|
|
|
for (n = 0; n < size;) {
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat(str, indent_str, indent_len);
|
2015-07-16 15:50:25 +03:00
|
|
|
n += rb_iseq_disasm_insn(str, code, n, iseq, child);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-07-25 05:18:32 +03:00
|
|
|
for (l = 0; l < RARRAY_LEN(child); l++) {
|
|
|
|
VALUE isv = rb_ary_entry(child, l);
|
2017-11-10 11:26:44 +03:00
|
|
|
if (done_iseq && st_is_member(done_iseq, (st_data_t)isv)) continue;
|
2018-04-04 14:00:39 +03:00
|
|
|
rb_str_cat_cstr(str, "\n");
|
|
|
|
rb_str_concat(str, rb_iseq_disasm_recursive(rb_iseq_check((rb_iseq_t *)isv), indent));
|
|
|
|
indent_str = RSTRING_PTR(indent);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2017-11-10 11:26:44 +03:00
|
|
|
if (done_iseq) st_free_table(done_iseq);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2018-04-04 14:00:39 +03:00
|
|
|
VALUE
|
|
|
|
rb_iseq_disasm(const rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
return rb_iseq_disasm_recursive(iseq, rb_str_new(0, 0));
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* iseq.disasm -> str
|
|
|
|
* iseq.disassemble -> str
|
|
|
|
*
|
|
|
|
* Returns the instruction sequence as a +String+ in human readable form.
|
|
|
|
*
|
|
|
|
* puts RubyVM::InstructionSequence.compile('1 + 2').disasm
|
|
|
|
*
|
|
|
|
* Produces:
|
|
|
|
*
|
|
|
|
* == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
|
|
|
|
* 0000 trace 1 ( 1)
|
|
|
|
* 0002 putobject 1
|
|
|
|
* 0004 putobject 2
|
|
|
|
* 0006 opt_plus <ic:1>
|
|
|
|
* 0008 leave
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
iseqw_disasm(VALUE self)
|
|
|
|
{
|
|
|
|
return rb_iseq_disasm(iseqw_check(self));
|
|
|
|
}
|
|
|
|
|
2017-12-23 15:48:24 +03:00
|
|
|
static int
|
2018-11-26 21:16:39 +03:00
|
|
|
iseq_iterate_children(const rb_iseq_t *iseq, void (*iter_func)(const rb_iseq_t *child_iseq, void *data), void *data)
|
2017-12-23 15:48:24 +03:00
|
|
|
{
|
2018-11-26 21:16:39 +03:00
|
|
|
unsigned int i;
|
|
|
|
VALUE *code = rb_iseq_original_iseq(iseq);
|
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
const rb_iseq_t *child;
|
|
|
|
VALUE all_children = rb_obj_hide(rb_ident_hash_new());
|
|
|
|
|
|
|
|
if (body->catch_table) {
|
|
|
|
for (i = 0; i < body->catch_table->size; i++) {
|
2019-05-31 09:58:50 +03:00
|
|
|
const struct iseq_catch_table_entry *entry =
|
|
|
|
UNALIGNED_MEMBER_PTR(body->catch_table, entries[i]);
|
2018-11-26 21:16:39 +03:00
|
|
|
child = entry->iseq;
|
|
|
|
if (child) {
|
|
|
|
if (rb_hash_aref(all_children, (VALUE)child) == Qnil) {
|
|
|
|
rb_hash_aset(all_children, (VALUE)child, Qtrue);
|
|
|
|
(*iter_func)(child, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<body->iseq_size;) {
|
|
|
|
VALUE insn = code[i];
|
|
|
|
int len = insn_len(insn);
|
|
|
|
const char *types = insn_op_types(insn);
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j=0; types[j]; j++) {
|
|
|
|
switch (types[j]) {
|
|
|
|
case TS_ISEQ:
|
|
|
|
child = (const rb_iseq_t *)code[i+j+1];
|
|
|
|
if (child) {
|
|
|
|
if (rb_hash_aref(all_children, (VALUE)child) == Qnil) {
|
|
|
|
rb_hash_aset(all_children, (VALUE)child, Qtrue);
|
|
|
|
(*iter_func)(child, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i += len;
|
|
|
|
}
|
|
|
|
|
2018-11-26 21:27:02 +03:00
|
|
|
return (int)RHASH_SIZE(all_children);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
yield_each_children(const rb_iseq_t *child_iseq, void *data)
|
|
|
|
{
|
|
|
|
rb_yield(iseqw_new(child_iseq));
|
2017-12-23 15:48:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* iseq.each_child{|child_iseq| ...} -> iseq
|
|
|
|
*
|
|
|
|
* Iterate all direct child instruction sequences.
|
|
|
|
* Iteration order is implementation/version defined
|
|
|
|
* so that people should not rely on the order.
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
iseqw_each_child(VALUE self)
|
|
|
|
{
|
|
|
|
const rb_iseq_t *iseq = iseqw_check(self);
|
2018-11-26 21:16:39 +03:00
|
|
|
iseq_iterate_children(iseq, yield_each_children, NULL);
|
2017-12-23 15:48:24 +03:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2017-12-23 17:46:59 +03:00
|
|
|
static void
|
|
|
|
push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE ary)
|
|
|
|
{
|
|
|
|
#define C(ev, cstr, l) if (events & ev) rb_ary_push(ary, rb_ary_new_from_args(2, l, ID2SYM(rb_intern(cstr))));
|
|
|
|
C(RUBY_EVENT_CLASS, "class", rb_iseq_first_lineno(iseq));
|
|
|
|
C(RUBY_EVENT_CALL, "call", rb_iseq_first_lineno(iseq));
|
|
|
|
C(RUBY_EVENT_B_CALL, "b_call", rb_iseq_first_lineno(iseq));
|
|
|
|
C(RUBY_EVENT_LINE, "line", INT2FIX(line));
|
|
|
|
C(RUBY_EVENT_END, "end", INT2FIX(line));
|
|
|
|
C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
|
|
|
|
C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
|
|
|
|
#undef C
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* iseq.trace_points -> ary
|
|
|
|
*
|
|
|
|
* Return trace points in the instruction sequence.
|
|
|
|
* Return an array of [line, event_symbol] pair.
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
iseqw_trace_points(VALUE self)
|
|
|
|
{
|
|
|
|
const rb_iseq_t *iseq = iseqw_check(self);
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2017-12-23 17:46:59 +03:00
|
|
|
unsigned int i;
|
|
|
|
VALUE ary = rb_ary_new();
|
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i=0; i<body->insns_info.size; i++) {
|
|
|
|
const struct iseq_insn_info_entry *entry = &body->insns_info.body[i];
|
2017-12-23 17:46:59 +03:00
|
|
|
if (entry->events) {
|
|
|
|
push_event_info(iseq, entry->events, entry->line_no, ary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2012-12-29 10:29:47 +04:00
|
|
|
/*
|
|
|
|
* Returns the instruction sequence containing the given proc or method.
|
|
|
|
*
|
|
|
|
* For example, using irb:
|
|
|
|
*
|
|
|
|
* # a proc
|
|
|
|
* > p = proc { num = 1 + 2 }
|
|
|
|
* > RubyVM::InstructionSequence.of(p)
|
|
|
|
* > #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>
|
|
|
|
*
|
|
|
|
* # for a method
|
|
|
|
* > def foo(bar); puts bar; end
|
|
|
|
* > RubyVM::InstructionSequence.of(method(:foo))
|
|
|
|
* > #=> <RubyVM::InstructionSequence:foo@(irb)>
|
|
|
|
*
|
|
|
|
* Using ::compile_file:
|
|
|
|
*
|
|
|
|
* # /tmp/iseq_of.rb
|
|
|
|
* def hello
|
|
|
|
* puts "hello, world"
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* $a_global_proc = proc { str = 'a' + 'b' }
|
|
|
|
*
|
|
|
|
* # in irb
|
|
|
|
* > require '/tmp/iseq_of.rb'
|
|
|
|
*
|
|
|
|
* # first the method hello
|
|
|
|
* > RubyVM::InstructionSequence.of(method(:hello))
|
|
|
|
* > #=> #<RubyVM::InstructionSequence:0x007fb73d7cb1d0>
|
|
|
|
*
|
|
|
|
* # then the global proc
|
|
|
|
* > RubyVM::InstructionSequence.of($a_global_proc)
|
|
|
|
* > #=> #<RubyVM::InstructionSequence:0x007fb73d7caf78>
|
|
|
|
*/
|
2012-11-30 22:02:43 +04:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_s_of(VALUE klass, VALUE body)
|
2012-11-30 22:02:43 +04:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
const rb_iseq_t *iseq = NULL;
|
2012-11-30 22:02:43 +04:00
|
|
|
|
|
|
|
rb_secure(1);
|
|
|
|
|
|
|
|
if (rb_obj_is_proc(body)) {
|
2018-11-27 05:45:25 +03:00
|
|
|
iseq = vm_proc_iseq(body);
|
2015-07-22 01:52:59 +03:00
|
|
|
|
2018-11-27 06:02:41 +03:00
|
|
|
if (!rb_obj_is_iseq((VALUE)iseq)) {
|
|
|
|
iseq = NULL;
|
2018-11-27 05:45:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rb_obj_is_method(body)) {
|
2018-11-27 06:02:41 +03:00
|
|
|
iseq = rb_method_iseq(body);
|
2018-11-27 05:45:25 +03:00
|
|
|
}
|
2018-11-27 06:19:06 +03:00
|
|
|
else if (rb_typeddata_is_instance_of(body, &iseqw_data_type)) {
|
2018-11-27 05:45:25 +03:00
|
|
|
return body;
|
2012-11-30 22:02:43 +04:00
|
|
|
}
|
2018-11-27 06:02:41 +03:00
|
|
|
|
|
|
|
return iseq ? iseqw_new(iseq) : Qnil;
|
2012-11-30 22:02:43 +04:00
|
|
|
}
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* InstructionSequence.disasm(body) -> str
|
|
|
|
* InstructionSequence.disassemble(body) -> str
|
|
|
|
*
|
|
|
|
* Takes +body+, a Method or Proc object, and returns a String with the
|
|
|
|
* human readable instructions for +body+.
|
|
|
|
*
|
|
|
|
* For a Method object:
|
|
|
|
*
|
|
|
|
* # /tmp/method.rb
|
|
|
|
* def hello
|
|
|
|
* puts "hello, world"
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* puts RubyVM::InstructionSequence.disasm(method(:hello))
|
|
|
|
*
|
|
|
|
* Produces:
|
|
|
|
*
|
|
|
|
* == disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
|
|
|
|
* 0000 trace 8 ( 1)
|
|
|
|
* 0002 trace 1 ( 2)
|
|
|
|
* 0004 putself
|
|
|
|
* 0005 putstring "hello, world"
|
|
|
|
* 0007 send :puts, 1, nil, 8, <ic:0>
|
|
|
|
* 0013 trace 16 ( 3)
|
|
|
|
* 0015 leave ( 2)
|
|
|
|
*
|
|
|
|
* For a Proc:
|
|
|
|
*
|
|
|
|
* # /tmp/proc.rb
|
|
|
|
* p = proc { num = 1 + 2 }
|
|
|
|
* puts RubyVM::InstructionSequence.disasm(p)
|
|
|
|
*
|
|
|
|
* Produces:
|
|
|
|
*
|
|
|
|
* == disasm: <RubyVM::InstructionSequence:block in <main>@/tmp/proc.rb>===
|
|
|
|
* == catch table
|
|
|
|
* | catch type: redo st: 0000 ed: 0012 sp: 0000 cont: 0000
|
|
|
|
* | catch type: next st: 0000 ed: 0012 sp: 0000 cont: 0012
|
|
|
|
* |------------------------------------------------------------------------
|
|
|
|
* local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
|
|
|
|
* [ 2] num
|
|
|
|
* 0000 trace 1 ( 1)
|
|
|
|
* 0002 putobject 1
|
|
|
|
* 0004 putobject 2
|
|
|
|
* 0006 opt_plus <ic:1>
|
|
|
|
* 0008 dup
|
2012-10-04 17:52:20 +04:00
|
|
|
* 0009 setlocal num, 0
|
2012-07-25 01:29:24 +04:00
|
|
|
* 0012 leave
|
|
|
|
*
|
|
|
|
*/
|
2007-12-24 12:09:21 +03:00
|
|
|
static VALUE
|
2015-07-22 01:52:59 +03:00
|
|
|
iseqw_s_disasm(VALUE klass, VALUE body)
|
2007-12-24 12:09:21 +03:00
|
|
|
{
|
2015-07-22 01:52:59 +03:00
|
|
|
VALUE iseqw = iseqw_s_of(klass, body);
|
|
|
|
return NIL_P(iseqw) ? Qnil : rb_iseq_disasm(iseqw_check(iseqw));
|
2007-12-24 12:09:21 +03:00
|
|
|
}
|
|
|
|
|
* include/ruby/{intern,ruby}.h, compile.[ch], error.c, eval.c,
eval_load.c, gc.c, iseq.c, main.c, parse.y, re.c, ruby.c,
yarvcore.[ch] (ruby_eval_tree, ruby_sourcefile, ruby_sourceline,
ruby_nerrs): purge global variables.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12700 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-05 12:12:18 +04:00
|
|
|
const char *
|
* 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
|
|
|
ruby_node_name(int node)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
switch (node) {
|
2007-08-06 08:09:56 +04:00
|
|
|
#include "node_name.inc"
|
2007-05-11 10:26:06 +04:00
|
|
|
default:
|
2018-04-27 16:14:09 +03:00
|
|
|
rb_bug("unknown node: %d", node);
|
2006-12-31 18:02:22 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DECL_SYMBOL(name) \
|
2019-04-23 02:23:04 +03:00
|
|
|
static ID sym_##name
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
#define INIT_SYMBOL(name) \
|
2019-04-23 02:23:04 +03:00
|
|
|
sym_##name = rb_intern(#name)
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
static VALUE
|
* compile.c, cont.c, gc.c, insns.def, iseq.c, iseq.h, process.c,
thread.c, vm.c, vm_core.h, vm_dump.c, vm_eval.c,
vm_insnhelper.c, vm_method.c, template/insns_info.inc.tmpl,
tool/instruction.rb: fixed types.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25030 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-09-22 00:58:26 +04:00
|
|
|
register_label(struct st_table *table, unsigned long idx)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2014-10-14 11:23:01 +04:00
|
|
|
VALUE sym = rb_str_intern(rb_sprintf("label_%lu", idx));
|
2006-12-31 18:02:22 +03:00
|
|
|
st_insert(table, idx, sym);
|
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
exception_type2symbol(VALUE type)
|
|
|
|
{
|
|
|
|
ID id;
|
2012-12-29 16:22:04 +04:00
|
|
|
switch (type) {
|
2008-06-09 13:25:32 +04:00
|
|
|
case CATCH_TYPE_RESCUE: CONST_ID(id, "rescue"); break;
|
|
|
|
case CATCH_TYPE_ENSURE: CONST_ID(id, "ensure"); break;
|
|
|
|
case CATCH_TYPE_RETRY: CONST_ID(id, "retry"); break;
|
|
|
|
case CATCH_TYPE_BREAK: CONST_ID(id, "break"); break;
|
|
|
|
case CATCH_TYPE_REDO: CONST_ID(id, "redo"); break;
|
|
|
|
case CATCH_TYPE_NEXT: CONST_ID(id, "next"); break;
|
2006-12-31 18:02:22 +03:00
|
|
|
default:
|
2018-04-27 16:14:09 +03:00
|
|
|
rb_bug("unknown exception type: %d", (int)type);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
return ID2SYM(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
cdhash_each(VALUE key, VALUE value, VALUE ary)
|
|
|
|
{
|
2009-02-26 07:23:21 +03:00
|
|
|
rb_ary_push(ary, obj_resurrect(key));
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(ary, value);
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2008-09-04 22:23:27 +04:00
|
|
|
static VALUE
|
2015-07-22 00:28:43 +03:00
|
|
|
iseq_data_to_ary(const rb_iseq_t *iseq)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-07-25 05:18:32 +03:00
|
|
|
unsigned int i;
|
|
|
|
long l;
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const iseq_body = iseq->body;
|
2018-01-09 17:05:21 +03:00
|
|
|
const struct iseq_insn_info_entry *prev_insn_info;
|
2011-08-26 23:04:39 +04:00
|
|
|
unsigned int pos;
|
2017-11-14 15:58:36 +03:00
|
|
|
int last_line = 0;
|
compile: translate iseq in-place
running "ruby -rpp -e 'pp GC.stat'", a reduction in
malloc usage is shown:
before:
:malloc_increase=>118784,
:oldmalloc_increase=>1178736,
after:
:malloc_increase=>99832,
:oldmalloc_increase=>1031976,
For "ruby -e exit", valgrind reports over 300K reduction in
overall allocations (and unnecessary memory copies).
before:
total heap usage: 49,622 allocs, 20,492 frees, 8,697,493 bytes allocated
after:
total heap usage: 48,935 allocs, 19,805 frees, 8,373,773 bytes allocated
(numbers from x86-64)
v2 changes based on ko1 recommendations [ruby-core:64883]:
- squashed in-place direct thread translation to avoid alloc+copy
- renamed rb_iseq_untranslate_threaded_code to rb_iseq_original_iseq,
cache new iseq->iseq_original field.
* compile.c (rb_iseq_translate_threaded_code): modify in-place w/o copy
(rb_vm_addr2insn): new function for debug
(rb_iseq_original_iseq): ditto
(iseq_set_sequence): assign iseq_encoded directly
[Feature #10185]
* vm_core (rb_iseq_t): move original ->iseq to bottom
* iseq.c (iseq_free, iseq_free): adjust for new layout
(rb_iseq_disasm): use original iseq for dump
(iseq_data_to_ary): ditto
(rb_iseq_line_trace_each): ditto
(rb_iseq_build_for_ruby2cext): use iseq_encoded directly
* vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47508 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-10 10:14:07 +04:00
|
|
|
VALUE *seq, *iseq_original;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
VALUE val = rb_ary_new();
|
2019-04-23 02:23:04 +03:00
|
|
|
ID type; /* Symbol */
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE locals = rb_ary_new();
|
2014-11-03 02:14:21 +03:00
|
|
|
VALUE params = rb_hash_new();
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
|
|
|
|
VALUE nbody;
|
|
|
|
VALUE exception = rb_ary_new(); /* [[....]] */
|
2007-07-02 01:43:30 +04:00
|
|
|
VALUE misc = rb_hash_new();
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2019-04-23 02:23:04 +03:00
|
|
|
static ID insn_syms[VM_INSTRUCTION_SIZE/2]; /* w/o-trace only */
|
2006-12-31 18:02:22 +03:00
|
|
|
struct st_table *labels_table = st_init_numtable();
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2007-07-02 03:57:04 +04:00
|
|
|
DECL_SYMBOL(top);
|
2006-12-31 18:02:22 +03:00
|
|
|
DECL_SYMBOL(method);
|
|
|
|
DECL_SYMBOL(block);
|
|
|
|
DECL_SYMBOL(class);
|
|
|
|
DECL_SYMBOL(rescue);
|
|
|
|
DECL_SYMBOL(ensure);
|
|
|
|
DECL_SYMBOL(eval);
|
2008-12-27 08:58:23 +03:00
|
|
|
DECL_SYMBOL(main);
|
2018-01-05 03:49:41 +03:00
|
|
|
DECL_SYMBOL(plain);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-07-02 03:57:04 +04:00
|
|
|
if (sym_top == 0) {
|
2006-12-31 18:02:22 +03:00
|
|
|
int i;
|
2018-01-17 18:28:37 +03:00
|
|
|
for (i=0; i<numberof(insn_syms); i++) {
|
2019-04-23 04:19:47 +03:00
|
|
|
insn_syms[i] = rb_intern(insn_name(i));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2007-07-02 03:57:04 +04:00
|
|
|
INIT_SYMBOL(top);
|
2006-12-31 18:02:22 +03:00
|
|
|
INIT_SYMBOL(method);
|
|
|
|
INIT_SYMBOL(block);
|
|
|
|
INIT_SYMBOL(class);
|
|
|
|
INIT_SYMBOL(rescue);
|
|
|
|
INIT_SYMBOL(ensure);
|
|
|
|
INIT_SYMBOL(eval);
|
2008-12-27 08:58:23 +03:00
|
|
|
INIT_SYMBOL(main);
|
2018-01-05 03:49:41 +03:00
|
|
|
INIT_SYMBOL(plain);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
/* type */
|
2018-05-12 04:24:18 +03:00
|
|
|
switch (iseq_body->type) {
|
2007-07-02 03:57:04 +04:00
|
|
|
case ISEQ_TYPE_TOP: type = sym_top; break;
|
|
|
|
case ISEQ_TYPE_METHOD: type = sym_method; break;
|
|
|
|
case ISEQ_TYPE_BLOCK: type = sym_block; break;
|
|
|
|
case ISEQ_TYPE_CLASS: type = sym_class; break;
|
|
|
|
case ISEQ_TYPE_RESCUE: type = sym_rescue; break;
|
|
|
|
case ISEQ_TYPE_ENSURE: type = sym_ensure; break;
|
|
|
|
case ISEQ_TYPE_EVAL: type = sym_eval; break;
|
2008-12-27 08:58:23 +03:00
|
|
|
case ISEQ_TYPE_MAIN: type = sym_main; break;
|
2018-01-05 03:49:41 +03:00
|
|
|
case ISEQ_TYPE_PLAIN: type = sym_plain; break;
|
2018-05-12 04:24:18 +03:00
|
|
|
default: rb_bug("unsupported iseq type: %d", (int)iseq_body->type);
|
2006-12-31 18:02:22 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/* locals */
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i=0; i<iseq_body->local_table_size; i++) {
|
|
|
|
ID lid = iseq_body->local_table[i];
|
2006-12-31 18:02:22 +03:00
|
|
|
if (lid) {
|
2014-12-02 01:32:56 +03:00
|
|
|
if (rb_id2str(lid)) {
|
|
|
|
rb_ary_push(locals, ID2SYM(lid));
|
|
|
|
}
|
|
|
|
else { /* hidden variable from id_internal() */
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_ary_push(locals, ULONG2NUM(iseq_body->local_table_size-i+1));
|
2014-12-02 01:32:56 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_ary_push(locals, ID2SYM(rb_intern("#arg_rest")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-03 02:14:21 +03:00
|
|
|
/* params */
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_param_keyword *const keyword = iseq_body->param.keyword;
|
2006-12-31 18:02:22 +03:00
|
|
|
int j;
|
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
if (iseq_body->param.flags.has_opt) {
|
|
|
|
int len = iseq_body->param.opt_num + 1;
|
|
|
|
VALUE arg_opt_labels = rb_ary_new2(len);
|
2014-12-04 01:16:58 +03:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
for (j = 0; j < len; j++) {
|
|
|
|
VALUE l = register_label(labels_table, iseq_body->param.opt_table[j]);
|
|
|
|
rb_ary_push(arg_opt_labels, l);
|
|
|
|
}
|
|
|
|
rb_hash_aset(params, ID2SYM(rb_intern("opt")), arg_opt_labels);
|
2014-12-04 01:16:58 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
/* commit */
|
2018-05-12 04:24:18 +03:00
|
|
|
if (iseq_body->param.flags.has_lead) rb_hash_aset(params, ID2SYM(rb_intern("lead_num")), INT2FIX(iseq_body->param.lead_num));
|
|
|
|
if (iseq_body->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_num")), INT2FIX(iseq_body->param.post_num));
|
|
|
|
if (iseq_body->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_start")), INT2FIX(iseq_body->param.post_start));
|
|
|
|
if (iseq_body->param.flags.has_rest) rb_hash_aset(params, ID2SYM(rb_intern("rest_start")), INT2FIX(iseq_body->param.rest_start));
|
|
|
|
if (iseq_body->param.flags.has_block) rb_hash_aset(params, ID2SYM(rb_intern("block_start")), INT2FIX(iseq_body->param.block_start));
|
|
|
|
if (iseq_body->param.flags.has_kw) {
|
2014-11-03 02:14:21 +03:00
|
|
|
VALUE keywords = rb_ary_new();
|
|
|
|
int i, j;
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i=0; i<keyword->required_num; i++) {
|
|
|
|
rb_ary_push(keywords, ID2SYM(keyword->table[i]));
|
2014-11-03 02:14:21 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
for (j=0; i<keyword->num; i++, j++) {
|
|
|
|
VALUE key = rb_ary_new_from_args(1, ID2SYM(keyword->table[i]));
|
|
|
|
if (keyword->default_values[j] != Qundef) {
|
|
|
|
rb_ary_push(key, keyword->default_values[j]);
|
2014-11-03 02:14:21 +03:00
|
|
|
}
|
|
|
|
rb_ary_push(keywords, key);
|
|
|
|
}
|
2014-12-04 01:16:58 +03:00
|
|
|
|
|
|
|
rb_hash_aset(params, ID2SYM(rb_intern("kwbits")),
|
2018-05-12 04:24:18 +03:00
|
|
|
INT2FIX(keyword->bits_start));
|
2014-11-03 02:14:21 +03:00
|
|
|
rb_hash_aset(params, ID2SYM(rb_intern("keyword")), keywords);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (iseq_body->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(keyword->rest_start));
|
|
|
|
if (iseq_body->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* body */
|
2015-07-22 00:28:43 +03:00
|
|
|
iseq_original = rb_iseq_original_iseq((rb_iseq_t *)iseq);
|
compile: translate iseq in-place
running "ruby -rpp -e 'pp GC.stat'", a reduction in
malloc usage is shown:
before:
:malloc_increase=>118784,
:oldmalloc_increase=>1178736,
after:
:malloc_increase=>99832,
:oldmalloc_increase=>1031976,
For "ruby -e exit", valgrind reports over 300K reduction in
overall allocations (and unnecessary memory copies).
before:
total heap usage: 49,622 allocs, 20,492 frees, 8,697,493 bytes allocated
after:
total heap usage: 48,935 allocs, 19,805 frees, 8,373,773 bytes allocated
(numbers from x86-64)
v2 changes based on ko1 recommendations [ruby-core:64883]:
- squashed in-place direct thread translation to avoid alloc+copy
- renamed rb_iseq_untranslate_threaded_code to rb_iseq_original_iseq,
cache new iseq->iseq_original field.
* compile.c (rb_iseq_translate_threaded_code): modify in-place w/o copy
(rb_vm_addr2insn): new function for debug
(rb_iseq_original_iseq): ditto
(iseq_set_sequence): assign iseq_encoded directly
[Feature #10185]
* vm_core (rb_iseq_t): move original ->iseq to bottom
* iseq.c (iseq_free, iseq_free): adjust for new layout
(rb_iseq_disasm): use original iseq for dump
(iseq_data_to_ary): ditto
(rb_iseq_line_trace_each): ditto
(rb_iseq_build_for_ruby2cext): use iseq_encoded directly
* vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47508 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-10 10:14:07 +04:00
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
for (seq = iseq_original; seq < iseq_original + iseq_body->iseq_size; ) {
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE insn = *seq++;
|
|
|
|
int j, len = insn_len(insn);
|
|
|
|
VALUE *nseq = seq + len - 1;
|
2007-05-11 10:26:06 +04:00
|
|
|
VALUE ary = rb_ary_new2(len);
|
|
|
|
|
2019-04-23 04:19:47 +03:00
|
|
|
rb_ary_push(ary, ID2SYM(insn_syms[insn%numberof(insn_syms)]));
|
2006-12-31 18:02:22 +03:00
|
|
|
for (j=0; j<len-1; j++, seq++) {
|
|
|
|
switch (insn_op_type(insn, j)) {
|
|
|
|
case TS_OFFSET: {
|
compile: translate iseq in-place
running "ruby -rpp -e 'pp GC.stat'", a reduction in
malloc usage is shown:
before:
:malloc_increase=>118784,
:oldmalloc_increase=>1178736,
after:
:malloc_increase=>99832,
:oldmalloc_increase=>1031976,
For "ruby -e exit", valgrind reports over 300K reduction in
overall allocations (and unnecessary memory copies).
before:
total heap usage: 49,622 allocs, 20,492 frees, 8,697,493 bytes allocated
after:
total heap usage: 48,935 allocs, 19,805 frees, 8,373,773 bytes allocated
(numbers from x86-64)
v2 changes based on ko1 recommendations [ruby-core:64883]:
- squashed in-place direct thread translation to avoid alloc+copy
- renamed rb_iseq_untranslate_threaded_code to rb_iseq_original_iseq,
cache new iseq->iseq_original field.
* compile.c (rb_iseq_translate_threaded_code): modify in-place w/o copy
(rb_vm_addr2insn): new function for debug
(rb_iseq_original_iseq): ditto
(iseq_set_sequence): assign iseq_encoded directly
[Feature #10185]
* vm_core (rb_iseq_t): move original ->iseq to bottom
* iseq.c (iseq_free, iseq_free): adjust for new layout
(rb_iseq_disasm): use original iseq for dump
(iseq_data_to_ary): ditto
(rb_iseq_line_trace_each): ditto
(rb_iseq_build_for_ruby2cext): use iseq_encoded directly
* vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47508 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-10 10:14:07 +04:00
|
|
|
unsigned long idx = nseq - iseq_original + *seq;
|
2007-05-11 10:26:06 +04:00
|
|
|
rb_ary_push(ary, register_label(labels_table, idx));
|
|
|
|
break;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
case TS_LINDEX:
|
|
|
|
case TS_NUM:
|
|
|
|
rb_ary_push(ary, INT2FIX(*seq));
|
|
|
|
break;
|
|
|
|
case TS_VALUE:
|
2009-02-18 08:33:36 +03:00
|
|
|
rb_ary_push(ary, obj_resurrect(*seq));
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
|
|
|
case TS_ISEQ:
|
|
|
|
{
|
2015-07-22 00:28:43 +03:00
|
|
|
const rb_iseq_t *iseq = (rb_iseq_t *)*seq;
|
2006-12-31 18:02:22 +03:00
|
|
|
if (iseq) {
|
2015-12-08 16:58:50 +03:00
|
|
|
VALUE val = iseq_data_to_ary(rb_iseq_check(iseq));
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(ary, val);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_ary_push(ary, Qnil);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TS_GENTRY:
|
|
|
|
{
|
2009-07-16 04:01:06 +04:00
|
|
|
struct rb_global_entry *entry = (struct rb_global_entry *)*seq;
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(ary, ID2SYM(entry->id));
|
|
|
|
}
|
|
|
|
break;
|
2013-08-20 21:41:13 +04:00
|
|
|
case TS_IC:
|
2018-03-19 21:21:54 +03:00
|
|
|
case TS_ISE:
|
2013-08-20 21:41:13 +04:00
|
|
|
{
|
|
|
|
union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)*seq;
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_ary_push(ary, INT2FIX(is - iseq_body->is_entries));
|
2013-08-20 21:41:13 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
break;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
case TS_CALLINFO:
|
|
|
|
{
|
2015-09-19 20:59:58 +03:00
|
|
|
struct rb_call_info *ci = (struct rb_call_info *)*seq;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
VALUE e = rb_hash_new();
|
2014-12-04 01:16:58 +03:00
|
|
|
int orig_argc = ci->orig_argc;
|
|
|
|
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
rb_hash_aset(e, ID2SYM(rb_intern("mid")), ci->mid ? ID2SYM(ci->mid) : Qnil);
|
2014-12-04 01:16:58 +03:00
|
|
|
rb_hash_aset(e, ID2SYM(rb_intern("flag")), UINT2NUM(ci->flag));
|
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
if (ci->flag & VM_CALL_KWARG) {
|
|
|
|
struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci;
|
2014-12-04 01:16:58 +03:00
|
|
|
int i;
|
2015-09-19 20:59:58 +03:00
|
|
|
VALUE kw = rb_ary_new2((long)ci_kw->kw_arg->keyword_len);
|
2014-12-04 01:16:58 +03:00
|
|
|
|
2015-09-19 20:59:58 +03:00
|
|
|
orig_argc -= ci_kw->kw_arg->keyword_len;
|
|
|
|
for (i = 0; i < ci_kw->kw_arg->keyword_len; i++) {
|
|
|
|
rb_ary_push(kw, ci_kw->kw_arg->keywords[i]);
|
2014-12-04 01:16:58 +03:00
|
|
|
}
|
|
|
|
rb_hash_aset(e, ID2SYM(rb_intern("kw_arg")), kw);
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")),
|
|
|
|
INT2FIX(orig_argc));
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
|
|
|
rb_ary_push(ary, e);
|
|
|
|
}
|
|
|
|
break;
|
2015-09-19 20:59:58 +03:00
|
|
|
case TS_CALLCACHE:
|
|
|
|
rb_ary_push(ary, Qfalse);
|
|
|
|
break;
|
2006-12-31 18:02:22 +03:00
|
|
|
case TS_ID:
|
|
|
|
rb_ary_push(ary, ID2SYM(*seq));
|
|
|
|
break;
|
|
|
|
case TS_CDHASH:
|
|
|
|
{
|
|
|
|
VALUE hash = *seq;
|
|
|
|
VALUE val = rb_ary_new();
|
|
|
|
int i;
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_hash_foreach(hash, cdhash_each, val);
|
|
|
|
|
|
|
|
for (i=0; i<RARRAY_LEN(val); i+=2) {
|
|
|
|
VALUE pos = FIX2INT(rb_ary_entry(val, i+1));
|
compile: translate iseq in-place
running "ruby -rpp -e 'pp GC.stat'", a reduction in
malloc usage is shown:
before:
:malloc_increase=>118784,
:oldmalloc_increase=>1178736,
after:
:malloc_increase=>99832,
:oldmalloc_increase=>1031976,
For "ruby -e exit", valgrind reports over 300K reduction in
overall allocations (and unnecessary memory copies).
before:
total heap usage: 49,622 allocs, 20,492 frees, 8,697,493 bytes allocated
after:
total heap usage: 48,935 allocs, 19,805 frees, 8,373,773 bytes allocated
(numbers from x86-64)
v2 changes based on ko1 recommendations [ruby-core:64883]:
- squashed in-place direct thread translation to avoid alloc+copy
- renamed rb_iseq_untranslate_threaded_code to rb_iseq_original_iseq,
cache new iseq->iseq_original field.
* compile.c (rb_iseq_translate_threaded_code): modify in-place w/o copy
(rb_vm_addr2insn): new function for debug
(rb_iseq_original_iseq): ditto
(iseq_set_sequence): assign iseq_encoded directly
[Feature #10185]
* vm_core (rb_iseq_t): move original ->iseq to bottom
* iseq.c (iseq_free, iseq_free): adjust for new layout
(rb_iseq_disasm): use original iseq for dump
(iseq_data_to_ary): ditto
(rb_iseq_line_trace_each): ditto
(rb_iseq_build_for_ruby2cext): use iseq_encoded directly
* vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47508 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-10 10:14:07 +04:00
|
|
|
unsigned long idx = nseq - iseq_original + pos;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
rb_ary_store(val, i+1,
|
|
|
|
register_label(labels_table, idx));
|
|
|
|
}
|
|
|
|
rb_ary_push(ary, val);
|
|
|
|
}
|
|
|
|
break;
|
2014-12-16 04:14:20 +03:00
|
|
|
case TS_FUNCPTR:
|
2014-12-16 08:54:32 +03:00
|
|
|
{
|
|
|
|
#if SIZEOF_VALUE <= SIZEOF_LONG
|
|
|
|
VALUE val = LONG2NUM((SIGNED_VALUE)*seq);
|
|
|
|
#else
|
|
|
|
VALUE val = LL2NUM((SIGNED_VALUE)*seq);
|
|
|
|
#endif
|
|
|
|
rb_ary_push(ary, val);
|
|
|
|
}
|
2014-12-16 04:14:20 +03:00
|
|
|
break;
|
2006-12-31 18:02:22 +03:00
|
|
|
default:
|
|
|
|
rb_bug("unknown operand: %c", insn_op_type(insn, j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rb_ary_push(body, ary);
|
|
|
|
}
|
|
|
|
|
|
|
|
nbody = body;
|
|
|
|
|
|
|
|
/* exception */
|
2018-05-12 04:24:18 +03:00
|
|
|
if (iseq_body->catch_table) for (i=0; i<iseq_body->catch_table->size; i++) {
|
2006-12-31 18:02:22 +03:00
|
|
|
VALUE ary = rb_ary_new();
|
2019-05-31 09:58:50 +03:00
|
|
|
const struct iseq_catch_table_entry *entry =
|
|
|
|
UNALIGNED_MEMBER_PTR(iseq_body->catch_table, entries[i]);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(ary, exception_type2symbol(entry->type));
|
|
|
|
if (entry->iseq) {
|
2015-12-08 16:58:50 +03:00
|
|
|
rb_ary_push(ary, iseq_data_to_ary(rb_iseq_check(entry->iseq)));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_ary_push(ary, Qnil);
|
|
|
|
}
|
|
|
|
rb_ary_push(ary, register_label(labels_table, entry->start));
|
|
|
|
rb_ary_push(ary, register_label(labels_table, entry->end));
|
|
|
|
rb_ary_push(ary, register_label(labels_table, entry->cont));
|
2014-12-04 01:16:58 +03:00
|
|
|
rb_ary_push(ary, UINT2NUM(entry->sp));
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(exception, ary);
|
|
|
|
}
|
|
|
|
|
2007-07-02 01:43:30 +04:00
|
|
|
/* make body with labels and insert line number */
|
2006-12-31 18:02:22 +03:00
|
|
|
body = rb_ary_new();
|
2018-01-09 17:05:21 +03:00
|
|
|
prev_insn_info = NULL;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-07-25 05:18:32 +03:00
|
|
|
for (l=0, pos=0; l<RARRAY_LEN(nbody); l++) {
|
2018-01-09 17:05:21 +03:00
|
|
|
const struct iseq_insn_info_entry *info;
|
2015-07-25 05:18:32 +03:00
|
|
|
VALUE ary = RARRAY_AREF(nbody, l);
|
* 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 label;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
if (st_lookup(labels_table, pos, &label)) {
|
2010-10-12 18:35:40 +04:00
|
|
|
rb_ary_push(body, (VALUE)label);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 17:05:21 +03:00
|
|
|
info = get_insn_info(iseq, pos);
|
2017-11-14 15:58:36 +03:00
|
|
|
|
2018-01-09 17:05:21 +03:00
|
|
|
if (prev_insn_info != info) {
|
|
|
|
int line = info->line_no;
|
|
|
|
rb_event_flag_t events = info->events;
|
|
|
|
|
|
|
|
if (line > 0 && last_line != line) {
|
|
|
|
rb_ary_push(body, INT2FIX(line));
|
|
|
|
last_line = line;
|
|
|
|
}
|
2017-11-14 15:58:36 +03:00
|
|
|
#define CHECK_EVENT(ev) if (events & ev) rb_ary_push(body, ID2SYM(rb_intern(#ev)));
|
2018-01-09 17:05:21 +03:00
|
|
|
CHECK_EVENT(RUBY_EVENT_LINE);
|
|
|
|
CHECK_EVENT(RUBY_EVENT_CLASS);
|
|
|
|
CHECK_EVENT(RUBY_EVENT_END);
|
|
|
|
CHECK_EVENT(RUBY_EVENT_CALL);
|
|
|
|
CHECK_EVENT(RUBY_EVENT_RETURN);
|
|
|
|
CHECK_EVENT(RUBY_EVENT_B_CALL);
|
|
|
|
CHECK_EVENT(RUBY_EVENT_B_RETURN);
|
2017-11-14 15:58:36 +03:00
|
|
|
#undef CHECK_EVENT
|
2018-01-09 17:05:21 +03:00
|
|
|
prev_insn_info = info;
|
2007-07-02 01:43:30 +04:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(body, ary);
|
2011-09-25 11:42:38 +04:00
|
|
|
pos += RARRAY_LENINT(ary); /* reject too huge data */
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2014-11-27 05:48:14 +03:00
|
|
|
RB_GC_GUARD(nbody);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
st_free_table(labels_table);
|
|
|
|
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq_body->param.size));
|
|
|
|
rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq_body->local_table_size));
|
|
|
|
rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq_body->stack_max));
|
2018-11-05 05:13:45 +03:00
|
|
|
rb_hash_aset(misc, ID2SYM(rb_intern("node_id")), INT2FIX(iseq_body->location.node_id));
|
2018-01-09 11:45:35 +03:00
|
|
|
rb_hash_aset(misc, ID2SYM(rb_intern("code_location")),
|
2017-12-05 11:56:50 +03:00
|
|
|
rb_ary_new_from_args(4,
|
2018-05-12 04:24:18 +03:00
|
|
|
INT2FIX(iseq_body->location.code_location.beg_pos.lineno),
|
|
|
|
INT2FIX(iseq_body->location.code_location.beg_pos.column),
|
|
|
|
INT2FIX(iseq_body->location.code_location.end_pos.lineno),
|
|
|
|
INT2FIX(iseq_body->location.code_location.end_pos.column)));
|
2007-05-11 10:26:06 +04:00
|
|
|
|
2009-02-22 17:23:33 +03:00
|
|
|
/*
|
2007-07-02 01:43:30 +04:00
|
|
|
* [:magic, :major_version, :minor_version, :format_type, :misc,
|
2012-06-04 06:49:37 +04:00
|
|
|
* :name, :path, :absolute_path, :start_lineno, :type, :locals, :args,
|
2007-07-02 01:43:30 +04:00
|
|
|
* :catch_table, :bytecode]
|
2006-12-31 18:02: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
|
|
|
rb_ary_push(val, rb_str_new2("YARVInstructionSequence/SimpleDataFormat"));
|
2010-10-31 04:42:54 +03:00
|
|
|
rb_ary_push(val, INT2FIX(ISEQ_MAJOR_VERSION)); /* major */
|
|
|
|
rb_ary_push(val, INT2FIX(ISEQ_MINOR_VERSION)); /* minor */
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(val, INT2FIX(1));
|
2007-07-02 01:43:30 +04:00
|
|
|
rb_ary_push(val, misc);
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_ary_push(val, iseq_body->location.label);
|
2017-06-01 03:05:33 +03:00
|
|
|
rb_ary_push(val, rb_iseq_path(iseq));
|
|
|
|
rb_ary_push(val, rb_iseq_realpath(iseq));
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_ary_push(val, iseq_body->location.first_lineno);
|
2019-04-23 02:23:04 +03:00
|
|
|
rb_ary_push(val, ID2SYM(type));
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(val, locals);
|
2014-11-03 02:14:21 +03:00
|
|
|
rb_ary_push(val, params);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_ary_push(val, exception);
|
|
|
|
rb_ary_push(val, body);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2008-11-28 07:19:37 +03:00
|
|
|
VALUE
|
2008-12-05 07:05:48 +03:00
|
|
|
rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
|
2008-11-28 07:19:37 +03:00
|
|
|
{
|
2011-12-05 13:50:12 +04:00
|
|
|
int i, r;
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
2018-05-16 04:40:44 +03:00
|
|
|
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
|
2018-05-12 04:24:18 +03:00
|
|
|
VALUE a, args = rb_ary_new2(body->param.size);
|
2011-12-26 18:20:15 +04:00
|
|
|
ID req, opt, rest, block, key, keyrest;
|
2008-11-28 07:19:37 +03:00
|
|
|
#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
|
2018-05-12 04:24:18 +03:00
|
|
|
#define PARAM_ID(i) body->local_table[(i)]
|
2008-11-28 07:19:37 +03:00
|
|
|
#define PARAM(i, type) ( \
|
|
|
|
PARAM_TYPE(type), \
|
2012-06-09 18:36:56 +04:00
|
|
|
rb_id2str(PARAM_ID(i)) ? \
|
2008-11-28 07:19:37 +03:00
|
|
|
rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
|
|
|
|
a)
|
|
|
|
|
|
|
|
CONST_ID(req, "req");
|
2008-12-05 07:05:48 +03:00
|
|
|
CONST_ID(opt, "opt");
|
|
|
|
if (is_proc) {
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i = 0; i < body->param.lead_num; i++) {
|
2008-12-05 07:05:48 +03:00
|
|
|
PARAM_TYPE(opt);
|
2012-06-09 18:36:56 +04:00
|
|
|
rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
|
2008-12-05 07:05:48 +03:00
|
|
|
rb_ary_push(args, a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i = 0; i < body->param.lead_num; i++) {
|
2008-12-05 07:05:48 +03:00
|
|
|
rb_ary_push(args, PARAM(i, req));
|
|
|
|
}
|
2008-11-28 07:19:37 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
r = body->param.lead_num + body->param.opt_num;
|
2011-12-05 13:50:12 +04:00
|
|
|
for (; i < r; i++) {
|
2008-11-28 07:19:37 +03:00
|
|
|
PARAM_TYPE(opt);
|
2012-06-09 18:36:56 +04:00
|
|
|
if (rb_id2str(PARAM_ID(i))) {
|
2008-11-28 07:19:37 +03:00
|
|
|
rb_ary_push(a, ID2SYM(PARAM_ID(i)));
|
|
|
|
}
|
|
|
|
rb_ary_push(args, a);
|
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->param.flags.has_rest) {
|
2008-11-28 07:19:37 +03:00
|
|
|
CONST_ID(rest, "rest");
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_ary_push(args, PARAM(body->param.rest_start, rest));
|
2008-11-28 07:19:37 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
r = body->param.post_start + body->param.post_num;
|
2008-12-05 07:05:48 +03:00
|
|
|
if (is_proc) {
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i = body->param.post_start; i < r; i++) {
|
2008-12-05 07:05:48 +03:00
|
|
|
PARAM_TYPE(opt);
|
2012-06-09 18:36:56 +04:00
|
|
|
rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
|
2008-12-05 07:05:48 +03:00
|
|
|
rb_ary_push(args, a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2018-05-12 04:24:18 +03:00
|
|
|
for (i = body->param.post_start; i < r; i++) {
|
2008-12-05 07:05:48 +03:00
|
|
|
rb_ary_push(args, PARAM(i, req));
|
|
|
|
}
|
2008-11-28 07:19:37 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->param.flags.has_kw) {
|
2013-03-12 17:20:50 +04:00
|
|
|
i = 0;
|
2018-05-16 04:40:44 +03:00
|
|
|
if (keyword->required_num > 0) {
|
2013-03-12 17:20:50 +04:00
|
|
|
ID keyreq;
|
|
|
|
CONST_ID(keyreq, "keyreq");
|
2018-05-16 04:40:44 +03:00
|
|
|
for (; i < keyword->required_num; i++) {
|
2013-03-12 17:20:50 +04:00
|
|
|
PARAM_TYPE(keyreq);
|
2018-05-16 04:40:44 +03:00
|
|
|
if (rb_id2str(keyword->table[i])) {
|
|
|
|
rb_ary_push(a, ID2SYM(keyword->table[i]));
|
2013-03-12 17:20:50 +04:00
|
|
|
}
|
|
|
|
rb_ary_push(args, a);
|
|
|
|
}
|
|
|
|
}
|
2011-12-26 18:20:15 +04:00
|
|
|
CONST_ID(key, "key");
|
2018-05-16 04:40:44 +03:00
|
|
|
for (; i < keyword->num; i++) {
|
2011-12-26 18:20:15 +04:00
|
|
|
PARAM_TYPE(key);
|
2018-05-16 04:40:44 +03:00
|
|
|
if (rb_id2str(keyword->table[i])) {
|
|
|
|
rb_ary_push(a, ID2SYM(keyword->table[i]));
|
2011-12-26 18:20:15 +04:00
|
|
|
}
|
|
|
|
rb_ary_push(args, a);
|
|
|
|
}
|
* rewrite method/block parameter fitting logic to optimize
keyword arguments/parameters and a splat argument.
[Feature #10440] (Details are described in this ticket)
Most of complex part is moved to vm_args.c.
Now, ISeq#to_a does not catch up new instruction format.
* vm_core.h: change iseq data structures.
* introduce rb_call_info_kw_arg_t to represent keyword arguments.
* add rb_call_info_t::kw_arg.
* rename rb_iseq_t::arg_post_len to rb_iseq_t::arg_post_num.
* rename rb_iseq_t::arg_keywords to arg_keyword_num.
* rename rb_iseq_t::arg_keyword to rb_iseq_t::arg_keyword_bits.
to represent keyword bitmap parameter index.
This bitmap parameter shows that which keyword parameters are given
or not given (0 for given).
It is refered by `checkkeyword' instruction described bellow.
* rename rb_iseq_t::arg_keyword_check to rb_iseq_t::arg_keyword_rest
to represent keyword rest parameter index.
* add rb_iseq_t::arg_keyword_default_values to represent default
keyword values.
* rename VM_CALL_ARGS_SKIP_SETUP to VM_CALL_ARGS_SIMPLE
to represent
(ci->flag & (SPLAT|BLOCKARG)) &&
ci->blockiseq == NULL &&
ci->kw_arg == NULL.
* vm_insnhelper.c, vm_args.c: rewrite with refactoring.
* rewrite splat argument code.
* rewrite keyword arguments/parameters code.
* merge method and block parameter fitting code into one code base.
* vm.c, vm_eval.c: catch up these changes.
* compile.c (new_callinfo): callinfo requires kw_arg parameter.
* compile.c (compile_array_): check the last argument Hash object or
not. If Hash object and all keys are Symbol literals, they are
compiled to keyword arguments.
* insns.def (checkkeyword): add new instruction.
This instruction check the availability of corresponding keyword.
For example, a method "def foo k1: 'v1'; end" is cimpiled to the
following instructions.
0000 checkkeyword 2, 0 # check k1 is given.
0003 branchif 9 # if given, jump to address #9
0005 putstring "v1"
0007 setlocal_OP__WC__0 3 # k1 = 'v1'
0009 trace 8
0011 putnil
0012 trace 16
0014 leave
* insns.def (opt_send_simple): removed and add new instruction
"opt_send_without_block".
* parse.y (new_args_tail_gen): reorder variables.
Before this patch, a method "def foo(k1: 1, kr1:, k2: 2, **krest, &b)"
has parameter variables "k1, kr1, k2, &b, internal_id, krest",
but this patch reorders to "kr1, k1, k2, internal_id, krest, &b".
(locate a block variable at last)
* parse.y (vtable_pop): added.
This function remove latest `n' variables from vtable.
* iseq.c: catch up iseq data changes.
* proc.c: ditto.
* class.c (keyword_error): export as rb_keyword_error().
* common.mk: depend vm_args.c for vm.o.
* hash.c (rb_hash_has_key): export.
* internal.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48239 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-11-02 21:02:55 +03:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->param.flags.has_kwrest) {
|
* rewrite method/block parameter fitting logic to optimize
keyword arguments/parameters and a splat argument.
[Feature #10440] (Details are described in this ticket)
Most of complex part is moved to vm_args.c.
Now, ISeq#to_a does not catch up new instruction format.
* vm_core.h: change iseq data structures.
* introduce rb_call_info_kw_arg_t to represent keyword arguments.
* add rb_call_info_t::kw_arg.
* rename rb_iseq_t::arg_post_len to rb_iseq_t::arg_post_num.
* rename rb_iseq_t::arg_keywords to arg_keyword_num.
* rename rb_iseq_t::arg_keyword to rb_iseq_t::arg_keyword_bits.
to represent keyword bitmap parameter index.
This bitmap parameter shows that which keyword parameters are given
or not given (0 for given).
It is refered by `checkkeyword' instruction described bellow.
* rename rb_iseq_t::arg_keyword_check to rb_iseq_t::arg_keyword_rest
to represent keyword rest parameter index.
* add rb_iseq_t::arg_keyword_default_values to represent default
keyword values.
* rename VM_CALL_ARGS_SKIP_SETUP to VM_CALL_ARGS_SIMPLE
to represent
(ci->flag & (SPLAT|BLOCKARG)) &&
ci->blockiseq == NULL &&
ci->kw_arg == NULL.
* vm_insnhelper.c, vm_args.c: rewrite with refactoring.
* rewrite splat argument code.
* rewrite keyword arguments/parameters code.
* merge method and block parameter fitting code into one code base.
* vm.c, vm_eval.c: catch up these changes.
* compile.c (new_callinfo): callinfo requires kw_arg parameter.
* compile.c (compile_array_): check the last argument Hash object or
not. If Hash object and all keys are Symbol literals, they are
compiled to keyword arguments.
* insns.def (checkkeyword): add new instruction.
This instruction check the availability of corresponding keyword.
For example, a method "def foo k1: 'v1'; end" is cimpiled to the
following instructions.
0000 checkkeyword 2, 0 # check k1 is given.
0003 branchif 9 # if given, jump to address #9
0005 putstring "v1"
0007 setlocal_OP__WC__0 3 # k1 = 'v1'
0009 trace 8
0011 putnil
0012 trace 16
0014 leave
* insns.def (opt_send_simple): removed and add new instruction
"opt_send_without_block".
* parse.y (new_args_tail_gen): reorder variables.
Before this patch, a method "def foo(k1: 1, kr1:, k2: 2, **krest, &b)"
has parameter variables "k1, kr1, k2, &b, internal_id, krest",
but this patch reorders to "kr1, k1, k2, internal_id, krest, &b".
(locate a block variable at last)
* parse.y (vtable_pop): added.
This function remove latest `n' variables from vtable.
* iseq.c: catch up iseq data changes.
* proc.c: ditto.
* class.c (keyword_error): export as rb_keyword_error().
* common.mk: depend vm_args.c for vm.o.
* hash.c (rb_hash_has_key): export.
* internal.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48239 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-11-02 21:02:55 +03:00
|
|
|
CONST_ID(keyrest, "keyrest");
|
2018-05-16 04:40:44 +03:00
|
|
|
rb_ary_push(args, PARAM(keyword->rest_start, keyrest));
|
2011-12-26 18:20:15 +04:00
|
|
|
}
|
2018-05-12 04:24:18 +03:00
|
|
|
if (body->param.flags.has_block) {
|
2008-11-28 07:19:37 +03:00
|
|
|
CONST_ID(block, "block");
|
2018-05-12 04:24:18 +03:00
|
|
|
rb_ary_push(args, PARAM(body->param.block_start, block));
|
2008-11-28 07:19:37 +03:00
|
|
|
}
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
2012-09-24 12:36:53 +04:00
|
|
|
VALUE
|
|
|
|
rb_iseq_defined_string(enum defined_type type)
|
|
|
|
{
|
|
|
|
static const char expr_names[][18] = {
|
|
|
|
"nil",
|
|
|
|
"instance-variable",
|
|
|
|
"local-variable",
|
|
|
|
"global-variable",
|
|
|
|
"class variable",
|
|
|
|
"constant",
|
|
|
|
"method",
|
|
|
|
"yield",
|
|
|
|
"super",
|
|
|
|
"self",
|
|
|
|
"true",
|
|
|
|
"false",
|
|
|
|
"assignment",
|
|
|
|
"expression",
|
|
|
|
};
|
|
|
|
const char *estr;
|
|
|
|
VALUE *defs, str;
|
|
|
|
|
|
|
|
if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) return 0;
|
|
|
|
estr = expr_names[type - 1];
|
|
|
|
if (!estr[0]) return 0;
|
|
|
|
defs = GET_VM()->defined_strings;
|
|
|
|
if (!defs) {
|
|
|
|
defs = ruby_xcalloc(numberof(expr_names), sizeof(VALUE));
|
|
|
|
GET_VM()->defined_strings = defs;
|
|
|
|
}
|
2012-09-25 03:17:59 +04:00
|
|
|
str = defs[type-1];
|
2012-09-24 12:36:53 +04:00
|
|
|
if (!str) {
|
2014-09-21 07:50:23 +04:00
|
|
|
str = rb_str_new_cstr(estr);
|
2012-09-24 12:36:53 +04:00
|
|
|
OBJ_FREEZE(str);
|
2012-09-25 03:17:59 +04:00
|
|
|
defs[type-1] = str;
|
2014-07-16 13:09:40 +04:00
|
|
|
rb_gc_register_mark_object(str);
|
2012-09-24 12:36:53 +04:00
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2018-08-23 11:32:30 +03:00
|
|
|
/* A map from encoded_insn to insn_data: decoded insn number, its len,
|
|
|
|
* non-trace version of encoded insn, and trace version. */
|
|
|
|
|
|
|
|
static st_table *encoded_insn_data;
|
|
|
|
typedef struct insn_data_struct {
|
|
|
|
int insn;
|
|
|
|
int insn_len;
|
|
|
|
void *notrace_encoded_insn;
|
|
|
|
void *trace_encoded_insn;
|
|
|
|
} insn_data_t;
|
|
|
|
static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_vm_encoded_insn_data_table_init(void)
|
|
|
|
{
|
|
|
|
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
|
|
|
|
const void * const *table = rb_vm_get_insns_address_table();
|
|
|
|
#define INSN_CODE(insn) ((VALUE)table[insn])
|
|
|
|
#else
|
|
|
|
#define INSN_CODE(insn) (insn)
|
|
|
|
#endif
|
|
|
|
st_data_t insn;
|
|
|
|
encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
|
|
|
|
|
|
|
|
for (insn = 0; insn < VM_INSTRUCTION_SIZE/2; insn++) {
|
|
|
|
st_data_t key1 = (st_data_t)INSN_CODE(insn);
|
|
|
|
st_data_t key2 = (st_data_t)INSN_CODE(insn + VM_INSTRUCTION_SIZE/2);
|
|
|
|
|
2018-08-23 11:49:23 +03:00
|
|
|
insn_data[insn].insn = (int)insn;
|
2018-08-23 11:32:30 +03:00
|
|
|
insn_data[insn].insn_len = insn_len(insn);
|
|
|
|
insn_data[insn].notrace_encoded_insn = (void *) key1;
|
|
|
|
insn_data[insn].trace_encoded_insn = (void *) key2;
|
|
|
|
|
|
|
|
st_add_direct(encoded_insn_data, key1, (st_data_t)&insn_data[insn]);
|
|
|
|
st_add_direct(encoded_insn_data, key2, (st_data_t)&insn_data[insn]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_vm_insn_addr2insn(const void *addr)
|
|
|
|
{
|
|
|
|
st_data_t key = (st_data_t)addr;
|
|
|
|
st_data_t val;
|
|
|
|
|
|
|
|
if (st_lookup(encoded_insn_data, key, &val)) {
|
|
|
|
insn_data_t *e = (insn_data_t *)val;
|
|
|
|
return (int)e->insn;
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr);
|
|
|
|
}
|
|
|
|
|
2018-08-23 11:32:31 +03:00
|
|
|
static inline int
|
|
|
|
encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon)
|
|
|
|
{
|
|
|
|
st_data_t key = (st_data_t)*iseq_encoded_insn;
|
|
|
|
st_data_t val;
|
2012-11-30 21:00:30 +04:00
|
|
|
|
2018-08-23 11:32:31 +03:00
|
|
|
if (st_lookup(encoded_insn_data, key, &val)) {
|
|
|
|
insn_data_t *e = (insn_data_t *)val;
|
|
|
|
*iseq_encoded_insn = (VALUE) (turnon ? e->trace_encoded_insn : e->notrace_encoded_insn);
|
|
|
|
return e->insn_len;
|
|
|
|
}
|
2018-03-15 02:27:10 +03:00
|
|
|
|
2018-08-23 11:32:31 +03:00
|
|
|
rb_bug("trace_instrument: invalid insn address: %p", (void *)*iseq_encoded_insn);
|
|
|
|
}
|
2017-11-14 15:58:36 +03:00
|
|
|
|
2018-10-20 08:33:04 +03:00
|
|
|
void
|
2018-10-20 08:44:12 +03:00
|
|
|
rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
|
2018-10-20 08:33:04 +03:00
|
|
|
{
|
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
|
|
|
|
encoded_iseq_trace_instrument(&iseq_encoded[pos], 0);
|
|
|
|
}
|
|
|
|
|
2018-11-26 21:16:39 +03:00
|
|
|
static int
|
2018-11-26 23:16:14 +03:00
|
|
|
iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
|
2018-11-26 21:16:39 +03:00
|
|
|
{
|
|
|
|
unsigned int pc;
|
|
|
|
int n = 0;
|
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
|
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
|
2018-11-26 21:16:39 +03:00
|
|
|
|
|
|
|
for (pc=0; pc<body->iseq_size;) {
|
2018-11-26 23:16:14 +03:00
|
|
|
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc);
|
|
|
|
rb_event_flag_t pc_events = entry->events;
|
|
|
|
rb_event_flag_t target_events = turnon_events;
|
|
|
|
unsigned int line = (int)entry->line_no;
|
|
|
|
|
|
|
|
if (target_line == 0 || target_line == line) {
|
|
|
|
/* ok */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
target_events &= ~RUBY_EVENT_LINE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pc_events & target_events) {
|
2018-11-26 21:16:39 +03:00
|
|
|
n++;
|
|
|
|
}
|
2018-12-06 13:52:27 +03:00
|
|
|
pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->aux.exec.global_trace_events));
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (n > 0) {
|
2018-12-06 13:52:27 +03:00
|
|
|
if (iseq->aux.exec.local_hooks == NULL) {
|
|
|
|
((rb_iseq_t *)iseq)->aux.exec.local_hooks = RB_ZALLOC(rb_hook_list_t);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
2018-12-06 13:52:27 +03:00
|
|
|
rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->aux.exec.local_hooks, tpval, target_line);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct trace_set_local_events_struct {
|
|
|
|
rb_event_flag_t turnon_events;
|
|
|
|
VALUE tpval;
|
2018-11-26 23:16:14 +03:00
|
|
|
unsigned int target_line;
|
2018-11-26 21:16:39 +03:00
|
|
|
int n;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
|
|
|
|
{
|
|
|
|
struct trace_set_local_events_struct *data = (struct trace_set_local_events_struct *)p;
|
2018-11-26 23:16:14 +03:00
|
|
|
data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line);
|
2018-11-26 21:16:39 +03:00
|
|
|
iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2018-11-26 23:16:14 +03:00
|
|
|
rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
|
2018-11-26 21:16:39 +03:00
|
|
|
{
|
2018-11-26 21:48:48 +03:00
|
|
|
struct trace_set_local_events_struct data;
|
|
|
|
data.turnon_events = turnon_events;
|
|
|
|
data.tpval = tpval;
|
2018-11-26 23:16:14 +03:00
|
|
|
data.target_line = target_line;
|
2018-11-26 21:48:48 +03:00
|
|
|
data.n = 0;
|
|
|
|
|
2018-11-26 21:16:39 +03:00
|
|
|
iseq_add_local_tracepoint_i(iseq, (void *)&data);
|
|
|
|
if (0) rb_funcall(Qnil, rb_intern("puts"), 1, rb_iseq_disasm(iseq)); /* for debug */
|
|
|
|
return data.n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
if (iseq->aux.exec.local_hooks) {
|
2018-11-26 21:16:39 +03:00
|
|
|
unsigned int pc;
|
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
|
|
|
|
rb_event_flag_t local_events = 0;
|
|
|
|
|
2018-12-06 13:52:27 +03:00
|
|
|
rb_hook_list_remove_tracepoint(iseq->aux.exec.local_hooks, tpval);
|
|
|
|
local_events = iseq->aux.exec.local_hooks->events;
|
2018-11-26 21:16:39 +03:00
|
|
|
|
|
|
|
if (local_events == 0) {
|
2018-12-06 13:52:27 +03:00
|
|
|
if (iseq->aux.exec.local_hooks->running == 0) {
|
|
|
|
rb_hook_list_free(iseq->aux.exec.local_hooks);
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
2018-12-06 13:52:27 +03:00
|
|
|
((rb_iseq_t *)iseq)->aux.exec.local_hooks = NULL;
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (pc = 0; pc<body->iseq_size;) {
|
|
|
|
rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
|
2018-12-06 13:52:27 +03:00
|
|
|
pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.exec.global_trace_events));
|
2018-11-26 21:16:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct trace_clear_local_events_struct {
|
|
|
|
VALUE tpval;
|
|
|
|
int n;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
iseq_remove_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
|
|
|
|
{
|
|
|
|
struct trace_clear_local_events_struct *data = (struct trace_clear_local_events_struct *)p;
|
|
|
|
data->n += iseq_remove_local_tracepoint(iseq, data->tpval);
|
|
|
|
iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval)
|
|
|
|
{
|
2018-11-26 21:48:48 +03:00
|
|
|
struct trace_clear_local_events_struct data;
|
|
|
|
data.tpval = tpval;
|
|
|
|
data.n = 0;
|
|
|
|
|
2018-11-26 21:16:39 +03:00
|
|
|
iseq_remove_local_tracepoint_i(iseq, (void *)&data);
|
|
|
|
return data.n;
|
|
|
|
}
|
|
|
|
|
2017-11-17 09:24:55 +03:00
|
|
|
void
|
2017-11-14 15:58:36 +03:00
|
|
|
rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
|
2012-11-30 21:00:30 +04:00
|
|
|
{
|
2018-12-06 13:52:27 +03:00
|
|
|
if (iseq->aux.exec.global_trace_events == turnon_events) {
|
2017-11-18 12:39:41 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-12-06 13:52:27 +03:00
|
|
|
|
|
|
|
if (!ISEQ_EXECUTABLE_P(iseq)) {
|
2017-11-27 03:43:23 +03:00
|
|
|
/* this is building ISeq */
|
|
|
|
return;
|
|
|
|
}
|
2017-11-18 12:39:41 +03:00
|
|
|
else {
|
2018-11-26 21:16:54 +03:00
|
|
|
unsigned int pc;
|
2018-05-12 04:24:18 +03:00
|
|
|
const struct rb_iseq_constant_body *const body = iseq->body;
|
|
|
|
VALUE *iseq_encoded = (VALUE *)body->iseq_encoded;
|
2018-11-26 21:16:39 +03:00
|
|
|
rb_event_flag_t enabled_events;
|
2018-12-06 13:52:27 +03:00
|
|
|
rb_event_flag_t local_events = iseq->aux.exec.local_hooks ? iseq->aux.exec.local_hooks->events : 0;
|
|
|
|
((rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events;
|
2018-11-26 21:16:39 +03:00
|
|
|
enabled_events = turnon_events | local_events;
|
|
|
|
|
|
|
|
for (pc=0; pc<body->iseq_size;) {
|
2018-11-26 21:16:54 +03:00
|
|
|
rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
|
2018-11-26 21:16:39 +03:00
|
|
|
pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & enabled_events);
|
2012-11-30 21:00:30 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-11-14 15:58:36 +03:00
|
|
|
trace_set_i(void *vstart, void *vend, size_t stride, void *data)
|
2012-11-30 21:00:30 +04:00
|
|
|
{
|
2017-11-14 15:58:36 +03:00
|
|
|
rb_event_flag_t turnon_events = *(rb_event_flag_t *)data;
|
2012-11-30 21:00:30 +04:00
|
|
|
|
2017-11-14 15:58:36 +03:00
|
|
|
VALUE v = (VALUE)vstart;
|
|
|
|
for (; v != (VALUE)vend; v += stride) {
|
2019-05-23 11:02:07 +03:00
|
|
|
void *ptr = asan_poisoned_object_p(v);
|
|
|
|
asan_unpoison_object(v, false);
|
2019-04-02 01:52:35 +03:00
|
|
|
|
2017-11-14 15:58:36 +03:00
|
|
|
if (rb_obj_is_iseq(v)) {
|
|
|
|
rb_iseq_trace_set(rb_iseq_check((rb_iseq_t *)v), turnon_events);
|
2012-11-30 21:00:30 +04:00
|
|
|
}
|
2019-04-02 01:52:35 +03:00
|
|
|
|
2019-05-29 07:12:15 +03:00
|
|
|
asan_poison_object_if(ptr, v);
|
2012-11-30 21:00:30 +04:00
|
|
|
}
|
2017-11-14 15:58:36 +03:00
|
|
|
return 0;
|
2012-11-30 21:00:30 +04:00
|
|
|
}
|
|
|
|
|
2017-11-14 15:58:36 +03:00
|
|
|
void
|
|
|
|
rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
|
2012-11-30 21:00:30 +04:00
|
|
|
{
|
2017-11-14 15:58:36 +03:00
|
|
|
rb_objspace_each_objects(trace_set_i, &turnon_events);
|
|
|
|
}
|
2012-11-30 21:00:30 +04:00
|
|
|
|
2018-06-23 17:11:19 +03:00
|
|
|
/* This is exported since Ruby 2.5 but not internally used for now. If you're going to use this, please
|
2018-11-26 21:16:39 +03:00
|
|
|
update `ruby_vm_event_enabled_global_flags` and set `mjit_call_p = FALSE` as well to cancel MJIT code. */
|
2017-11-14 15:58:36 +03:00
|
|
|
void
|
|
|
|
rb_iseq_trace_on_all(void)
|
|
|
|
{
|
|
|
|
rb_iseq_trace_set_all(RUBY_EVENT_TRACEPOINT_ALL);
|
2012-11-30 21:00:30 +04:00
|
|
|
}
|
|
|
|
|
2015-12-08 08:27:10 +03:00
|
|
|
VALUE
|
|
|
|
rb_iseqw_local_variables(VALUE iseqval)
|
|
|
|
{
|
|
|
|
return rb_iseq_local_variables(iseqw_check(iseqval));
|
|
|
|
}
|
|
|
|
|
2015-12-08 16:58:50 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2015-12-09 18:10:57 +03:00
|
|
|
* iseq.to_binary(extra_data = nil) -> binary str
|
2015-12-08 16:58:50 +03:00
|
|
|
*
|
|
|
|
* Returns serialized iseq binary format data as a String object.
|
2015-12-14 05:52:14 +03:00
|
|
|
* A corresponding iseq object is created by
|
2015-12-09 18:10:57 +03:00
|
|
|
* RubyVM::InstructionSequence.load_from_binary() method.
|
2015-12-08 16:58:50 +03:00
|
|
|
*
|
|
|
|
* String extra_data will be saved with binary data.
|
|
|
|
* You can access this data with
|
2015-12-09 18:10:57 +03:00
|
|
|
* RubyVM::InstructionSequence.load_from_binary_extra_data(binary).
|
2015-12-09 05:41:14 +03:00
|
|
|
*
|
|
|
|
* Note that the translated binary data is not portable.
|
|
|
|
* You can not move this binary data to another machine.
|
2015-12-09 18:10:57 +03:00
|
|
|
* You can not use the binary data which is created by another
|
2015-12-09 05:41:14 +03:00
|
|
|
* version/another architecture of Ruby.
|
2015-12-08 16:58:50 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
2015-12-09 18:10:57 +03:00
|
|
|
iseqw_to_binary(int argc, VALUE *argv, VALUE self)
|
2015-12-08 16:58:50 +03:00
|
|
|
{
|
2018-12-06 10:49:24 +03:00
|
|
|
VALUE opt = !rb_check_arity(argc, 0, 1) ? Qnil : argv[0];
|
2018-09-13 16:59:25 +03:00
|
|
|
return rb_iseq_ibf_dump(iseqw_check(self), opt);
|
2015-12-08 16:58:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2015-12-09 18:10:57 +03:00
|
|
|
* RubyVM::InstructionSequence.load_from_binary(binary) -> iseq
|
2015-12-08 16:58:50 +03:00
|
|
|
*
|
|
|
|
* Load an iseq object from binary format String object
|
2015-12-09 18:10:57 +03:00
|
|
|
* created by RubyVM::InstructionSequence.to_binary.
|
2015-12-09 05:41:14 +03:00
|
|
|
*
|
|
|
|
* This loader does not have a verifier, so that loading broken/modified
|
|
|
|
* binary causes critical problem.
|
|
|
|
*
|
|
|
|
* You should not load binary data provided by others.
|
|
|
|
* You should use binary data translated by yourself.
|
2015-12-08 16:58:50 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
2015-12-09 18:10:57 +03:00
|
|
|
iseqw_s_load_from_binary(VALUE self, VALUE str)
|
2015-12-08 16:58:50 +03:00
|
|
|
{
|
2018-09-13 16:59:25 +03:00
|
|
|
return iseqw_new(rb_iseq_ibf_load(str));
|
2015-12-08 16:58:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2015-12-09 18:10:57 +03:00
|
|
|
* RubyVM::InstructionSequence.load_from_binary_extra_data(binary) -> str
|
2015-12-08 16:58:50 +03:00
|
|
|
*
|
|
|
|
* Load extra data embed into binary format String object.
|
|
|
|
*/
|
|
|
|
static VALUE
|
2015-12-09 18:10:57 +03:00
|
|
|
iseqw_s_load_from_binary_extra_data(VALUE self, VALUE str)
|
2015-12-08 16:58:50 +03:00
|
|
|
{
|
2018-09-13 16:59:25 +03:00
|
|
|
return rb_iseq_ibf_load_extra_data(str);
|
2015-12-08 16:58:50 +03:00
|
|
|
}
|
|
|
|
|
2018-01-09 17:05:23 +03:00
|
|
|
#if VM_INSN_INFO_TABLE_IMPL == 2
|
|
|
|
|
|
|
|
/* An implementation of succinct bit-vector for insn_info table.
|
|
|
|
*
|
|
|
|
* A succinct bit-vector is a small and efficient data structure that provides
|
|
|
|
* a bit-vector augmented with an index for O(1) rank operation:
|
|
|
|
*
|
|
|
|
* rank(bv, n): the number of 1's within a range from index 0 to index n
|
|
|
|
*
|
|
|
|
* This can be used to lookup insn_info table from PC.
|
|
|
|
* For example, consider the following iseq and insn_info_table:
|
|
|
|
*
|
|
|
|
* iseq insn_info_table
|
|
|
|
* PC insn+operand position lineno event
|
|
|
|
* 0: insn1 0: 1 [Li]
|
|
|
|
* 2: insn2 2: 2 [Li] <= (A)
|
|
|
|
* 5: insn3 8: 3 [Li] <= (B)
|
|
|
|
* 8: insn4
|
|
|
|
*
|
|
|
|
* In this case, a succinct bit-vector whose indexes 0, 2, 8 is "1" and
|
|
|
|
* other indexes is "0", i.e., "101000001", is created.
|
|
|
|
* To lookup the lineno of insn2, calculate rank("10100001", 2) = 2, so
|
|
|
|
* the line (A) is the entry in question.
|
|
|
|
* To lookup the lineno of insn4, calculate rank("10100001", 8) = 3, so
|
|
|
|
* the line (B) is the entry in question.
|
|
|
|
*
|
|
|
|
* A naive implementatoin of succinct bit-vector works really well
|
|
|
|
* not only for large size but also for small size. However, it has
|
|
|
|
* tiny overhead for very small size. So, this implementation consist
|
|
|
|
* of two parts: one part is the "immediate" table that keeps rank result
|
|
|
|
* as a raw table, and the other part is a normal succinct bit-vector.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define IMMEDIATE_TABLE_SIZE 54 /* a multiple of 9, and < 128 */
|
|
|
|
|
|
|
|
struct succ_index_table {
|
|
|
|
uint64_t imm_part[IMMEDIATE_TABLE_SIZE / 9];
|
|
|
|
struct succ_dict_block {
|
|
|
|
unsigned int rank;
|
|
|
|
uint64_t small_block_ranks; /* 9 bits * 7 = 63 bits */
|
|
|
|
uint64_t bits[512/64];
|
2018-01-13 14:45:25 +03:00
|
|
|
} succ_part[FLEX_ARY_LEN];
|
2018-01-19 06:19:58 +03:00
|
|
|
};
|
2018-01-09 17:05:23 +03:00
|
|
|
|
|
|
|
#define imm_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (7 * (i))
|
2018-01-10 08:57:15 +03:00
|
|
|
#define imm_block_rank_get(v, i) (((int)((v) >> ((i) * 7))) & 0x7f)
|
2018-01-09 17:05:23 +03:00
|
|
|
#define small_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (9 * ((i) - 1))
|
2018-01-10 08:57:15 +03:00
|
|
|
#define small_block_rank_get(v, i) ((i) == 0 ? 0 : (((int)((v) >> (((i) - 1) * 9))) & 0x1ff))
|
2018-01-09 17:05:23 +03:00
|
|
|
|
|
|
|
static struct succ_index_table *
|
|
|
|
succ_index_table_create(int max_pos, int *data, int size)
|
|
|
|
{
|
|
|
|
const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
|
|
|
|
const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
|
|
|
|
struct succ_index_table *sd = ruby_xcalloc(imm_size * sizeof(uint64_t) + succ_size * sizeof(struct succ_dict_block), 1); /* zero cleared */
|
|
|
|
int i, j, k, r;
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
for (j = 0; j < imm_size; j++) {
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
|
if (r < size && data[r] == j * 9 + i) r++;
|
|
|
|
imm_block_rank_set(sd->imm_part[j], i, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (k = 0; k < succ_size; k++) {
|
|
|
|
struct succ_dict_block *sd_block = &sd->succ_part[k];
|
|
|
|
int small_rank = 0;
|
|
|
|
sd_block->rank = r;
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
|
|
uint64_t bits = 0;
|
|
|
|
if (j) small_block_rank_set(sd_block->small_block_ranks, j, small_rank);
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
|
|
if (r < size && data[r] == k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE) {
|
2018-01-10 08:57:15 +03:00
|
|
|
bits |= ((uint64_t)1) << i;
|
2018-01-09 17:05:23 +03:00
|
|
|
r++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sd_block->bits[j] = bits;
|
|
|
|
small_rank += rb_popcount64(bits);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int *
|
|
|
|
succ_index_table_invert(int max_pos, struct succ_index_table *sd, int size)
|
|
|
|
{
|
|
|
|
const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
|
|
|
|
const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
|
|
|
|
unsigned int *positions = ruby_xmalloc(sizeof(unsigned int) * size), *p;
|
|
|
|
int i, j, k, r = -1;
|
|
|
|
p = positions;
|
|
|
|
for (j = 0; j < imm_size; j++) {
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
|
int nr = imm_block_rank_get(sd->imm_part[j], i);
|
|
|
|
if (r != nr) *p++ = j * 9 + i;
|
|
|
|
r = nr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (k = 0; k < succ_size; k++) {
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
|
|
for (i = 0; i < 64; i++) {
|
2018-01-10 08:57:15 +03:00
|
|
|
if (sd->succ_part[k].bits[j] & (((uint64_t)1) << i)) {
|
2018-01-09 17:05:23 +03:00
|
|
|
*p++ = k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return positions;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
succ_index_lookup(const struct succ_index_table *sd, int x)
|
|
|
|
{
|
|
|
|
if (x < IMMEDIATE_TABLE_SIZE) {
|
|
|
|
const int i = x / 9;
|
|
|
|
const int j = x % 9;
|
|
|
|
return imm_block_rank_get(sd->imm_part[i], j);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const int block_index = (x - IMMEDIATE_TABLE_SIZE) / 512;
|
|
|
|
const struct succ_dict_block *block = &sd->succ_part[block_index];
|
|
|
|
const int block_bit_index = (x - IMMEDIATE_TABLE_SIZE) % 512;
|
|
|
|
const int small_block_index = block_bit_index / 64;
|
|
|
|
const int small_block_popcount = small_block_rank_get(block->small_block_ranks, small_block_index);
|
|
|
|
const int popcnt = rb_popcount64(block->bits[small_block_index] << (63 - block_bit_index % 64));
|
|
|
|
|
|
|
|
return block->rank + small_block_popcount + popcnt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-07-25 01:29:24 +04:00
|
|
|
/*
|
|
|
|
* Document-class: RubyVM::InstructionSequence
|
|
|
|
*
|
|
|
|
* The InstructionSequence class represents a compiled sequence of
|
2012-12-29 11:44:54 +04:00
|
|
|
* instructions for the Ruby Virtual Machine.
|
|
|
|
*
|
|
|
|
* With it, you can get a handle to the instructions that make up a method or
|
|
|
|
* a proc, compile strings of Ruby code down to VM instructions, and
|
|
|
|
* disassemble instruction sequences to strings for easy inspection. It is
|
|
|
|
* mostly useful if you want to learn how the Ruby VM works, but it also lets
|
|
|
|
* you control various settings for the Ruby iseq compiler.
|
|
|
|
*
|
|
|
|
* You can find the source for the VM instructions in +insns.def+ in the Ruby
|
|
|
|
* source.
|
|
|
|
*
|
|
|
|
* The instruction sequence results will almost certainly change as Ruby
|
|
|
|
* changes, so example output in this documentation may be different from what
|
|
|
|
* you see.
|
2012-07-25 01:29:24 +04:00
|
|
|
*/
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
|
|
|
Init_ISeq(void)
|
|
|
|
{
|
2011-12-30 09:55:37 +04:00
|
|
|
/* declare ::RubyVM::InstructionSequence */
|
2008-06-29 21:26:16 +04:00
|
|
|
rb_cISeq = rb_define_class_under(rb_cRubyVM, "InstructionSequence", rb_cObject);
|
2016-08-22 03:02:59 +03:00
|
|
|
rb_undef_alloc_func(rb_cISeq);
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_define_method(rb_cISeq, "inspect", iseqw_inspect, 0);
|
|
|
|
rb_define_method(rb_cISeq, "disasm", iseqw_disasm, 0);
|
|
|
|
rb_define_method(rb_cISeq, "disassemble", iseqw_disasm, 0);
|
|
|
|
rb_define_method(rb_cISeq, "to_a", iseqw_to_a, 0);
|
|
|
|
rb_define_method(rb_cISeq, "eval", iseqw_eval, 0);
|
2007-01-17 11:48:52 +03:00
|
|
|
|
2015-12-09 18:10:57 +03:00
|
|
|
rb_define_method(rb_cISeq, "to_binary", iseqw_to_binary, -1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "load_from_binary", iseqw_s_load_from_binary, 1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "load_from_binary_extra_data", iseqw_s_load_from_binary_extra_data, 1);
|
2015-12-08 16:59:15 +03:00
|
|
|
|
2015-12-08 16:58:50 +03:00
|
|
|
|
2012-11-30 22:02:43 +04:00
|
|
|
/* location APIs */
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_define_method(rb_cISeq, "path", iseqw_path, 0);
|
|
|
|
rb_define_method(rb_cISeq, "absolute_path", iseqw_absolute_path, 0);
|
|
|
|
rb_define_method(rb_cISeq, "label", iseqw_label, 0);
|
|
|
|
rb_define_method(rb_cISeq, "base_label", iseqw_base_label, 0);
|
|
|
|
rb_define_method(rb_cISeq, "first_lineno", iseqw_first_lineno, 0);
|
2017-12-23 17:46:59 +03:00
|
|
|
rb_define_method(rb_cISeq, "trace_points", iseqw_trace_points, 0);
|
2017-12-23 15:48:24 +03:00
|
|
|
rb_define_method(rb_cISeq, "each_child", iseqw_each_child, 0);
|
2012-11-30 22:02:43 +04:00
|
|
|
|
2010-10-31 04:42:54 +03:00
|
|
|
#if 0 /* TBD */
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_define_private_method(rb_cISeq, "marshal_dump", iseqw_marshal_dump, 0);
|
|
|
|
rb_define_private_method(rb_cISeq, "marshal_load", iseqw_marshal_load, 1);
|
2007-12-24 12:09:21 +03:00
|
|
|
/* disable this feature because there is no verifier. */
|
2017-12-05 11:56:50 +03:00
|
|
|
rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1);
|
2017-12-05 11:58:57 +03:00
|
|
|
#endif
|
2008-06-01 23:55:25 +04:00
|
|
|
(void)iseq_s_load;
|
2007-12-24 12:09:21 +03:00
|
|
|
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "new", iseqw_s_compile, -1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "compile_file", iseqw_s_compile_file, -1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "compile_option", iseqw_s_compile_option_get, 0);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "compile_option=", iseqw_s_compile_option_set, 1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "disasm", iseqw_s_disasm, 1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "disassemble", iseqw_s_disasm, 1);
|
|
|
|
rb_define_singleton_method(rb_cISeq, "of", iseqw_s_of, 1);
|
2016-07-13 08:26:00 +03:00
|
|
|
|
|
|
|
rb_undef_method(CLASS_OF(rb_cISeq), "translate");
|
|
|
|
rb_undef_method(CLASS_OF(rb_cISeq), "load_iseq");
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|