* eval_method.c: renamed from vm_method.c. "vm_method.c" is included

by "vm.c".
* vm_eval.c: added.  Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
  id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
  blockinlining.c: fix for above changes.  and do some refactoring.
  this changes improve rb_yield() performance.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2008-05-24 17:50:17 +00:00
Родитель 582da7dac7
Коммит 59c061235f
18 изменённых файлов: 633 добавлений и 1946 удалений

Просмотреть файл

@ -1,3 +1,19 @@
Sun May 25 02:37:25 2008 Koichi Sasada <ko1@atdot.net>
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
Sat May 24 22:32:49 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* object.c (rb_cstr_to_dbl): should clear errno before calling

Просмотреть файл

@ -195,7 +195,7 @@ invoke_Integer_times_special_block(VALUE num)
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
argv[0] = INT2FIX(0);
argv[1] = num;
val = vm_yield(th, 2, argv);
val = rb_yield_values(2, argv);
if (val == Qundef) {
return num;
}
@ -314,7 +314,7 @@ invoke_Range_each_special_block(VALUE range,
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
argv[0] = beg;
argv[1] = end;
val = vm_yield(th, 2, argv);
val = rb_yield_values(2, argv);
if (val == Qundef) {
return range;
}
@ -444,7 +444,7 @@ invoke_Array_each_special_block(VALUE ary)
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
argv[0] = 0;
argv[1] = ary;
val = vm_yield(th, 2, argv);
val = rb_yield_values(2, argv);
if (val == Qundef) {
return ary;
}

Просмотреть файл

@ -470,7 +470,7 @@ eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}eval_intern.h \
{$(VPATH)}util.h {$(VPATH)}signal.h {$(VPATH)}vm_core.h \
{$(VPATH)}debug.h {$(VPATH)}vm_opts.h {$(VPATH)}id.h \
{$(VPATH)}thread_$(THREAD_MODEL).h {$(VPATH)}dln.h \
{$(VPATH)}eval_error.c {$(VPATH)}eval_method.c {$(VPATH)}eval_safe.c \
{$(VPATH)}eval_error.c {$(VPATH)}eval_safe.c \
{$(VPATH)}eval_jump.c
load.$(OBJEXT): {$(VPATH)}load.c {$(VPATH)}eval_intern.h \
{$(VPATH)}ruby.h {$(VPATH)}config.h {$(VPATH)}defines.h \
@ -647,7 +647,8 @@ vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
{$(VPATH)}vm_core.h {$(VPATH)}debug.h {$(VPATH)}vm_opts.h {$(VPATH)}id.h \
{$(VPATH)}thread_$(THREAD_MODEL).h {$(VPATH)}dln.h {$(VPATH)}vm.h \
{$(VPATH)}vm_insnhelper.c {$(VPATH)}insns.inc {$(VPATH)}vm_evalbody.c \
{$(VPATH)}vmtc.inc {$(VPATH)}vm.inc {$(VPATH)}insns.def
{$(VPATH)}vmtc.inc {$(VPATH)}vm.inc {$(VPATH)}insns.def \
{$(VPATH)}vm_method.c {$(VPATH)}vm_eval.c
vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c {$(VPATH)}ruby.h \
{$(VPATH)}config.h {$(VPATH)}defines.h {$(VPATH)}missing.h \
{$(VPATH)}intern.h {$(VPATH)}st.h {$(VPATH)}node.h {$(VPATH)}vm_core.h \

Просмотреть файл

@ -26,12 +26,8 @@
#define va_init_list(a,b) va_start(a)
#endif
/* iseq.c */
VALUE iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt);
/* vm.c */
VALUE vm_eval(void *);
/* types */
typedef struct iseq_link_element {
@ -294,12 +290,11 @@ int
iseq_translate_threaded_code(rb_iseq_t *iseq)
{
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
extern const void **vm_get_insns_address_table(void);
#if OPT_DIRECT_THREADED_CODE
const void *const *table = (const void **)vm_eval(0);
const void * const *table = vm_get_insns_address_table();
#else
extern const void *const *get_insns_address_table();
const void *const *table = get_insns_address_table();
const void * const *table = vm_get_insns_address_table();
#endif
int i;

1538
eval.c

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -3,34 +3,6 @@
* included by eval.c
*/
const char *
rb_sourcefile(void)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
if (cfp) {
return RSTRING_PTR(cfp->iseq->filename);
}
else {
return 0;
}
}
int
rb_sourceline(void)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
if (cfp) {
return vm_get_sourceline(cfp);
}
else {
return 0;
}
}
static void
warn_printf(const char *fmt, ...)
{
@ -79,6 +51,12 @@ get_backtrace(VALUE info)
return rb_check_backtrace(info);
}
VALUE
rb_get_backtrace(VALUE info)
{
return get_backtrace(info);
}
static void
set_backtrace(VALUE info, VALUE bt)
{

Просмотреть файл

@ -183,16 +183,9 @@ enum ruby_tag_type {
#define GET_THROWOBJ_CATCH_POINT(obj) ((VALUE*)RNODE((obj))->u2.value)
#define GET_THROWOBJ_STATE(obj) ((int)RNODE((obj))->u3.value)
#define SCOPE_TEST(f) \
(ruby_cref()->nd_visi & (f))
#define SCOPE_CHECK(f) \
(ruby_cref()->nd_visi == (f))
#define SCOPE_SET(f) \
{ \
ruby_cref()->nd_visi = (f); \
}
#define SCOPE_TEST(f) (vm_cref()->nd_visi & (f))
#define SCOPE_CHECK(f) (vm_cref()->nd_visi == (f))
#define SCOPE_SET(f) (vm_cref()->nd_visi = (f))
#define CHECK_STACK_OVERFLOW(cfp, margin) do \
if (((VALUE *)(cfp)->sp) + (margin) + sizeof(rb_control_frame_t) >= ((VALUE *)cfp)) { \
@ -220,21 +213,16 @@ VALUE rb_make_exception(int argc, VALUE *argv);
NORETURN(void rb_fiber_start(void));
NORETURN(void rb_raise_jump(VALUE));
NORETURN(void rb_print_undef(VALUE, ID, int));
NORETURN(void vm_localjump_error(const char *,VALUE, int));
NORETURN(void vm_jump_tag_but_local_jump(int, VALUE));
NODE *vm_cref_push(rb_thread_t * th, VALUE, int);
NODE *vm_set_special_cref(rb_thread_t *th, VALUE *lfp, NODE *cref_stack);
VALUE vm_make_jump_tag_but_local_jump(int state, VALUE val);
NODE *ruby_cref(void);
NODE *vm_cref(void);
rb_control_frame_t *vm_get_ruby_level_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
VALUE rb_obj_is_proc(VALUE);
void rb_vm_check_redefinition_opt_method(const NODE *node);
VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, const rb_block_t *blockptr, VALUE filename);
void rb_thread_terminate_all(void);
void rb_vm_set_eval_stack(rb_thread_t *, VALUE iseq, const NODE *cref);
VALUE rb_vm_top_self();
VALUE rb_vm_cbase(void);

Просмотреть файл

@ -5,162 +5,6 @@
#include "eval_intern.h"
NORETURN(static VALUE rb_f_throw _((int, VALUE *)));
/*
* call-seq:
* throw(symbol [, obj])
*
* Transfers control to the end of the active +catch+ block
* waiting for _symbol_. Raises +NameError+ if there
* is no +catch+ block for the symbol. The optional second
* parameter supplies a return value for the +catch+ block,
* which otherwise defaults to +nil+. For examples, see
* <code>Kernel::catch</code>.
*/
static VALUE
rb_f_throw(int argc, VALUE *argv)
{
VALUE tag, value;
rb_thread_t *th = GET_THREAD();
struct rb_vm_tag *tt = th->tag;
rb_scan_args(argc, argv, "11", &tag, &value);
while (tt) {
if (tt->tag == tag) {
tt->retval = value;
break;
}
tt = tt->prev;
}
if (!tt) {
VALUE desc = rb_inspect(tag);
rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
}
rb_trap_restore_mask();
th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);
JUMP_TAG(TAG_THROW);
#ifndef __GNUC__
return Qnil; /* not reached */
#endif
}
void
rb_throw(const char *tag, VALUE val)
{
VALUE argv[2];
argv[0] = ID2SYM(rb_intern(tag));
argv[1] = val;
rb_f_throw(2, argv);
}
void
rb_throw_obj(VALUE tag, VALUE val)
{
VALUE argv[2];
argv[0] = tag;
argv[1] = val;
rb_f_throw(2, argv);
}
/*
* call-seq:
* catch(symbol) {| | block } > obj
*
* +catch+ executes its block. If a +throw+ is
* executed, Ruby searches up its stack for a +catch+ block
* with a tag corresponding to the +throw+'s
* _symbol_. If found, that block is terminated, and
* +catch+ returns the value given to +throw+. If
* +throw+ is not called, the block terminates normally, and
* the value of +catch+ is the value of the last expression
* evaluated. +catch+ expressions may be nested, and the
* +throw+ call need not be in lexical scope.
*
* def routine(n)
* puts n
* throw :done if n <= 0
* routine(n-1)
* end
*
*
* catch(:done) { routine(3) }
*
* <em>produces:</em>
*
* 3
* 2
* 1
* 0
*/
static VALUE
rb_f_catch(int argc, VALUE *argv)
{
VALUE tag;
int state;
VALUE val = Qnil; /* OK */
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *saved_cfp = th->cfp;
if (argc == 0) {
tag = rb_obj_alloc(rb_cObject);
}
else {
rb_scan_args(argc, argv, "01", &tag);
}
PUSH_TAG();
th->tag->tag = tag;
if ((state = EXEC_TAG()) == 0) {
val = rb_yield_0(1, &tag);
}
else if (state == TAG_THROW && RNODE(th->errinfo)->u1.value == tag) {
th->cfp = saved_cfp;
val = th->tag->retval;
th->errinfo = Qnil;
state = 0;
}
POP_TAG();
if (state)
JUMP_TAG(state);
return val;
}
static VALUE
catch_null_i(VALUE dmy)
{
return rb_funcall(Qnil, rb_intern("catch"), 0, 0);
}
static VALUE
catch_i(VALUE tag)
{
return rb_funcall(Qnil, rb_intern("catch"), 1, tag);
}
VALUE
rb_catch(const char *tag, VALUE (*func)(), VALUE data)
{
if (!tag) {
return rb_iterate(catch_null_i, 0, func, data);
}
return rb_iterate(catch_i, ID2SYM(rb_intern(tag)), func, data);
}
VALUE
rb_catch_obj(VALUE tag, VALUE (*func)(), VALUE data)
{
return rb_iterate((VALUE (*)_((VALUE)))catch_i, tag, func, data);
}
/* exit */
void
@ -303,7 +147,5 @@ rb_exec_end_proc(void)
void
Init_jump(void)
{
rb_define_global_function("catch", rb_f_catch, -1);
rb_define_global_function("throw", rb_f_throw, -1);
rb_define_global_function("at_exit", rb_f_at_exit, 0);
}

3
id.c
Просмотреть файл

@ -63,4 +63,7 @@ Init_id(void)
idSend = rb_intern("send");
id__send__ = rb_intern("__send__");
idRespond_to = rb_intern("respond_to?");
idInitialize = rb_intern("initialize");
}

3
id.h
Просмотреть файл

@ -50,5 +50,6 @@ extern ID idBitblt;
extern ID idAnswer;
extern ID idSend;
extern ID id__send__;
extern ID idRespond_to;
extern ID idInitialize;
#endif /* RUBY_ID_H */

8
proc.c
Просмотреть файл

@ -1176,10 +1176,12 @@ rb_method_call(int argc, VALUE *argv, VALUE method)
}
}
if ((state = EXEC_TAG()) == 0) {
VALUE rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
int argc, const VALUE *argv, const NODE *body, int nosuper);
PASS_PASSED_BLOCK();
result = vm_call0(GET_THREAD(),
data->oclass, data->recv, data->id, data->oid,
argc, argv, data->body, 0);
result = rb_vm_call(GET_THREAD(), data->oclass, data->recv, data->id, data->oid,
argc, argv, data->body, 0);
}
POP_TAG();
if (safe >= 0)

Просмотреть файл

@ -1,7 +1,7 @@
#define RUBY_VERSION "1.9.0"
#define RUBY_RELEASE_DATE "2008-05-24"
#define RUBY_RELEASE_DATE "2008-05-25"
#define RUBY_VERSION_CODE 190
#define RUBY_RELEASE_CODE 20080524
#define RUBY_RELEASE_CODE 20080525
#define RUBY_PATCHLEVEL 0
#define RUBY_VERSION_MAJOR 1
@ -9,7 +9,7 @@
#define RUBY_VERSION_TEENY 0
#define RUBY_RELEASE_YEAR 2008
#define RUBY_RELEASE_MONTH 5
#define RUBY_RELEASE_DAY 24
#define RUBY_RELEASE_DAY 25
#ifdef RUBY_EXTERN
RUBY_EXTERN const char ruby_version[];

238
vm.c
Просмотреть файл

@ -16,6 +16,7 @@
#include "insnhelper.h"
#include "vm_insnhelper.c"
#include "vm_eval.c"
#define BUFSIZE 0x100
#define PROCDEBUG 0
@ -58,8 +59,8 @@ rb_vm_set_finish_env(rb_thread_t * th)
return Qtrue;
}
void
rb_vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
static void
vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
{
rb_iseq_t *iseq;
GetISeqPtr(iseqval, iseq);
@ -76,8 +77,8 @@ rb_vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
th->cfp->sp, 0, iseq->local_size);
}
void
rb_vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref)
static void
vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref)
{
rb_iseq_t *iseq;
rb_block_t * const block = th->base_block;
@ -411,152 +412,18 @@ vm_make_proc(rb_thread_t *th,
return procval;
}
/* C -> Ruby: method */
VALUE
vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
int argc, const VALUE *argv, const NODE *body, int nosuper)
{
VALUE val;
rb_block_t *blockptr = 0;
if (0) printf("id: %s, nd: %s, argc: %d, passed: %p\n",
rb_id2name(id), ruby_node_name(nd_type(body)),
argc, th->passed_block);
if (th->passed_block) {
blockptr = th->passed_block;
th->passed_block = 0;
}
switch (nd_type(body)) {
case RUBY_VM_METHOD_NODE:{
rb_control_frame_t *reg_cfp;
VALUE iseqval = (VALUE)body->nd_body;
int i;
rb_vm_set_finish_env(th);
reg_cfp = th->cfp;
CHECK_STACK_OVERFLOW(reg_cfp, argc + 1);
*reg_cfp->sp++ = recv;
for (i = 0; i < argc; i++) {
*reg_cfp->sp++ = argv[i];
}
vm_setup_method(th, reg_cfp, argc, blockptr, 0, iseqval, recv, klass);
val = vm_eval_body(th);
break;
}
case NODE_CFUNC: {
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
{
rb_control_frame_t *reg_cfp = th->cfp;
rb_control_frame_t *cfp =
vm_push_frame(th, 0, FRAME_MAGIC_CFUNC,
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
cfp->method_id = id;
cfp->method_class = klass;
val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv);
if (reg_cfp != th->cfp + 1) {
SDR2(reg_cfp);
SDR2(th->cfp-5);
rb_bug("cfp consistency error - call0");
th->cfp = reg_cfp;
}
vm_pop_frame(th);
}
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
break;
}
case NODE_ATTRSET:{
if (argc != 1) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
}
val = rb_ivar_set(recv, body->nd_vid, argv[0]);
break;
}
case NODE_IVAR: {
if (argc != 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
argc);
}
val = rb_attr_get(recv, body->nd_vid);
break;
}
case NODE_BMETHOD:{
val = vm_call_bmethod(th, id, body->nd_cval,
recv, klass, argc, (VALUE *)argv, blockptr);
break;
}
default:
rb_bug("unsupported: vm_call0(%s)", ruby_node_name(nd_type(body)));
}
RUBY_VM_CHECK_INTS();
return val;
}
static VALUE
vm_call_super(rb_thread_t * const th, const int argc, const VALUE * const argv)
{
VALUE recv = th->cfp->self;
VALUE klass;
ID id;
NODE *body;
rb_control_frame_t *cfp = th->cfp;
if (!cfp->iseq) {
klass = cfp->method_class;
klass = RCLASS_SUPER(klass);
if (klass == 0) {
klass = vm_search_normal_superclass(cfp->method_class, recv);
}
id = cfp->method_id;
}
else {
rb_bug("vm_call_super: should not be reached");
}
body = rb_method_node(klass, id); /* this returns NODE_METHOD */
if (body) {
body = body->nd_body;
}
else {
dp(recv);
dp(klass);
dpi(id);
rb_bug("vm_call_super: not found");
}
return vm_call0(th, klass, recv, id, id, argc, argv, body, CALL_SUPER);
}
VALUE
rb_call_super(int argc, const VALUE *argv)
{
PASS_PASSED_BLOCK();
return vm_call_super(GET_THREAD(), argc, argv);
}
/* C -> Ruby: block */
static inline VALUE
invoke_block_from_c(rb_thread_t *th, rb_block_t *block,
invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
VALUE self, int argc, const VALUE *argv,
rb_block_t *blockptr, const NODE *cref)
const rb_block_t *blockptr, const NODE *cref)
{
if (BUILTIN_TYPE(block->iseq) != T_NODE) {
rb_iseq_t *iseq = block->iseq;
rb_control_frame_t *cfp = th->cfp;
int i, opt_pc;
const int arg_size = iseq->arg_size;
const int type = block_proc_is_lambda(block->proc) ? FRAME_MAGIC_LAMBDA : FRAME_MAGIC_BLOCK;
const rb_iseq_t *iseq = block->iseq;
const rb_control_frame_t *cfp = th->cfp;
int i, opt_pc, arg_size = iseq->arg_size;
int type = block_proc_is_lambda(block->proc) ? FRAME_MAGIC_LAMBDA : FRAME_MAGIC_BLOCK;
rb_vm_set_finish_env(th);
@ -585,10 +452,10 @@ invoke_block_from_c(rb_thread_t *th, rb_block_t *block,
}
}
static inline rb_block_t *
static inline const rb_block_t *
check_block(rb_thread_t *th)
{
rb_block_t *blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
const rb_block_t *blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
if (blockptr == 0) {
vm_localjump_error("no block given", Qnil, 0);
@ -597,17 +464,17 @@ check_block(rb_thread_t *th)
return blockptr;
}
VALUE
static inline VALUE
vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref)
{
rb_block_t *blockptr = check_block(th);
const rb_block_t *blockptr = check_block(th);
return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, cref);
}
VALUE
static inline VALUE
vm_yield(rb_thread_t *th, int argc, const VALUE *argv)
{
rb_block_t *blockptr = check_block(th);
const rb_block_t *blockptr = check_block(th);
return invoke_block_from_c(th, blockptr, blockptr->self, argc, argv, 0, 0);
}
@ -654,7 +521,7 @@ vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
/* special variable */
VALUE
static VALUE
vm_cfp_svar_get(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key)
{
while (cfp->pc == 0) {
@ -663,7 +530,7 @@ vm_cfp_svar_get(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key)
return lfp_svar_get(th, cfp->lfp, key);
}
void
static void
vm_cfp_svar_set(rb_thread_t *th, rb_control_frame_t *cfp, VALUE key, const VALUE val)
{
while (cfp->pc == 0) {
@ -713,10 +580,10 @@ rb_lastline_set(VALUE val)
/* backtrace */
int
vm_get_sourceline(rb_control_frame_t *cfp)
vm_get_sourceline(const rb_control_frame_t *cfp)
{
int line_no = 0;
rb_iseq_t *iseq = cfp->iseq;
const rb_iseq_t *iseq = cfp->iseq;
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
int i;
@ -736,7 +603,7 @@ vm_get_sourceline(rb_control_frame_t *cfp)
static VALUE
vm_backtrace_each(rb_thread_t *th,
rb_control_frame_t *limit_cfp, rb_control_frame_t *cfp,
const rb_control_frame_t *limit_cfp, const rb_control_frame_t *cfp,
const char * file, int line_no, VALUE ary)
{
VALUE str;
@ -765,12 +632,12 @@ vm_backtrace_each(rb_thread_t *th,
return rb_ary_reverse(ary);
}
VALUE
static inline VALUE
vm_backtrace(rb_thread_t *th, int lev)
{
VALUE ary;
rb_control_frame_t *cfp = th->cfp;
rb_control_frame_t *top_of_cfp = (void *)(th->stack + th->stack_size);
const rb_control_frame_t *cfp = th->cfp;
const rb_control_frame_t *top_of_cfp = (void *)(th->stack + th->stack_size);
top_of_cfp -= 2;
if (lev < 0) {
@ -792,26 +659,36 @@ vm_backtrace(rb_thread_t *th, int lev)
return ary;
}
#if 0
static void
check_svar(void)
const char *
rb_sourcefile(void)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp = th->cfp;
while ((void *)(cfp + 1) < (void *)(th->stack + th->stack_size)) {
/* printf("cfp: %p\n", cfp->type); */
if (cfp->lfp && cfp->lfp[-1] != Qnil &&
TYPE(cfp->lfp[-1]) != T_NODE) {
/* dp(cfp->lfp[-1]); */
rb_bug("!!!invalid svar!!!");
}
cfp++;
rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
if (cfp) {
return RSTRING_PTR(cfp->iseq->filename);
}
else {
return 0;
}
}
int
rb_sourceline(void)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
if (cfp) {
return vm_get_sourceline(cfp);
}
else {
return 0;
}
}
#endif
NODE *
ruby_cref(void)
vm_cref(void)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
@ -830,7 +707,7 @@ debug_cref(NODE *cref)
}
#endif
NODE *
static NODE *
vm_cref_push(rb_thread_t *th, VALUE klass, int noex)
{
NODE *cref = NEW_BLOCK(klass);
@ -973,7 +850,7 @@ rb_iter_break(void)
VALUE ruby_vm_redefined_flag = 0;
static st_table *vm_opt_method_table = 0;
void
static void
rb_vm_check_redefinition_opt_method(const NODE *node)
{
VALUE bop;
@ -1130,7 +1007,7 @@ vm_init_redefined_flag(void)
*/
VALUE
static VALUE
vm_eval_body(rb_thread_t *th)
{
int state;
@ -1341,7 +1218,7 @@ rb_iseq_eval(VALUE iseqval)
VALUE val;
volatile VALUE tmp;
rb_vm_set_top_stack(th, iseqval);
vm_set_top_stack(th, iseqval);
if (!rb_const_defined(rb_cObject, rb_intern("TOPLEVEL_BINDING"))) {
rb_define_global_const("TOPLEVEL_BINDING", rb_binding_new());
@ -1388,9 +1265,9 @@ rb_frame_method_id_and_class(ID *idp, VALUE *klassp)
}
VALUE
rb_thread_current_status(rb_thread_t *th)
rb_thread_current_status(const rb_thread_t *th)
{
rb_control_frame_t *cfp = th->cfp;
const rb_control_frame_t *cfp = th->cfp;
VALUE str = Qnil;
if (cfp->iseq != 0) {
@ -1416,12 +1293,13 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
const rb_block_t *blockptr, VALUE filename)
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *reg_cfp = th->cfp;
const rb_control_frame_t *reg_cfp = th->cfp;
volatile VALUE iseqval = rb_iseq_new(0, filename, filename, 0, ISEQ_TYPE_TOP);
VALUE val;
vm_push_frame(th, DATA_PTR(iseqval), FRAME_MAGIC_TOP,
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
val = (*func)(arg);
vm_pop_frame(th);
@ -1429,7 +1307,7 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
}
int
rb_vm_cfunc_funcall_p(rb_control_frame_t * cfp)
rb_vm_cfunc_funcall_p(const rb_control_frame_t *cfp)
{
if (vm_cfunc_flags(cfp) & (VM_CALL_FCALL_BIT | VM_CALL_VCALL_BIT))
return Qtrue;

Просмотреть файл

@ -297,6 +297,7 @@ typedef struct rb_vm_struct {
VALUE thgroup_default;
VALUE last_status; /* $? */
int running;
int thread_abort_on_exception;
unsigned long trace_flag;
@ -605,19 +606,10 @@ void rb_enable_interrupt(void);
void rb_disable_interrupt(void);
int rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp);
VALUE vm_eval_body(rb_thread_t *th);
VALUE vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
int argc, const VALUE *argv, rb_block_t *blockptr);
VALUE vm_make_proc(rb_thread_t *th, rb_control_frame_t *cfp, const rb_block_t *block);
VALUE vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp);
VALUE vm_backtrace(rb_thread_t *, int);
VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv);
VALUE vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref);
VALUE vm_call0(rb_thread_t *th, VALUE klass, VALUE recv, VALUE id, ID oid,
int argc, const VALUE *argv, const NODE *body, int nosuper);
int vm_get_sourceline(rb_control_frame_t *);
NOINLINE(void rb_gc_save_machine_context(rb_thread_t *));

Просмотреть файл

@ -97,6 +97,8 @@ control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
iseq_name = "<ifunc>";
}
else {
int vm_get_sourceline(rb_control_frame_t *);
pc = cfp->pc - cfp->iseq->iseq_encoded;
iseq_name = RSTRING_PTR(cfp->iseq->name);
line = vm_get_sourceline(cfp);
@ -579,7 +581,7 @@ rb_vm_bugreport(void)
int i;
SDR();
bt = vm_backtrace(th, 0);
bt = rb_make_backtrace(th, 0);
if (TYPE(bt) == T_ARRAY)
for (i = 0; i < RARRAY_LEN(bt); i++) {
dp(RARRAY_PTR(bt)[i]);

Просмотреть файл

@ -26,7 +26,7 @@
/* #define DECL_SC_REG(r, reg) VALUE reg_##r */
#if !OPT_CALL_THREADED_CODE
VALUE
static VALUE
vm_eval(rb_thread_t *th, VALUE initial)
{
@ -140,3 +140,9 @@ vm_eval(rb_thread_t *th, VALUE initial)
return ret;
}
#endif
const void **
vm_get_insns_address_table(void)
{
return (const void **)vm_eval(0, 0);
}

Просмотреть файл

@ -100,7 +100,7 @@ vm_pop_frame(rb_thread_t *th)
static inline int
vm_callee_setup_arg(rb_thread_t *th, const rb_iseq_t * iseq,
int orig_argc, VALUE * orig_argv, rb_block_t **block)
int orig_argc, VALUE * orig_argv, const rb_block_t **block)
{
const int m = iseq->argc;
@ -426,8 +426,8 @@ vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
}
static inline void
vm_setup_method(rb_thread_t * const th, rb_control_frame_t * const cfp,
const int argc, rb_block_t *blockptr, const VALUE flag,
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
const int argc, const rb_block_t *blockptr, const VALUE flag,
const VALUE iseqval, const VALUE recv, const VALUE klass)
{
rb_iseq_t *iseq;
@ -648,7 +648,7 @@ block_proc_is_lambda(const VALUE procval)
}
static inline VALUE
vm_yield_with_cfunc(rb_thread_t *th, rb_block_t *block,
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
VALUE self, int argc, const VALUE *argv)
{
NODE *ifunc = (NODE *) block->iseq;
@ -679,7 +679,7 @@ vm_yield_with_cfunc(rb_thread_t *th, rb_block_t *block,
static inline int
vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq,
int orig_argc, VALUE *argv,
rb_block_t *blockptr, int lambda)
const rb_block_t *blockptr, int lambda)
{
if (0) { /* for debug */
printf(" argc: %d\n", orig_argc);

Просмотреть файл

@ -1,12 +1,19 @@
/* -*-c-*- */
/*
* This file is included by eval.c
* This file is included by vm_eval.c
*/
#define CACHE_SIZE 0x800
#define CACHE_MASK 0x7ff
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
static void rb_vm_check_redefinition_opt_method(const NODE *node);
static ID __send__, object_id;
static ID removed, singleton_removed, undefined, singleton_undefined;
static ID eqq, each, aref, aset, match, missing;
static ID added, singleton_added;
struct cache_entry { /* method hash table. */
ID mid; /* method's id */
ID mid0; /* method's original id */
@ -16,7 +23,8 @@ struct cache_entry { /* method hash table. */
};
static struct cache_entry cache[CACHE_SIZE];
static int ruby_running = 0;
#define ruby_running (GET_VM()->running)
/* int ruby_running = 0; */
void
rb_clear_cache(void)
@ -154,7 +162,7 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
}
}
}
if (klass == rb_cObject && node && mid == init) {
if (klass == rb_cObject && node && mid == idInitialize) {
rb_warn("redefining Object#initialize may cause infinite loop");
}
@ -304,7 +312,7 @@ remove_method(VALUE klass, ID mid)
}
if (OBJ_FROZEN(klass))
rb_error_frozen("class/module");
if (mid == object_id || mid == __send__ || mid == init) {
if (mid == object_id || mid == __send__ || mid == idInitialize) {
rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
}
if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
@ -471,7 +479,7 @@ rb_undef(VALUE klass, ID id)
rb_id2name(id));
}
rb_frozen_class_p(klass);
if (id == object_id || id == __send__ || id == init) {
if (id == object_id || id == __send__ || id == idInitialize) {
rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
}
body = search_method(klass, id, &origin);
@ -560,6 +568,160 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
return mod;
}
/*
* call-seq:
* mod.method_defined?(symbol) => true or false
*
* Returns +true+ if the named method is defined by
* _mod_ (or its included modules and, if _mod_ is a class,
* its ancestors). Public and protected methods are matched.
*
* module A
* def method1() end
* end
* class B
* def method2() end
* end
* class C < B
* include A
* def method3() end
* end
*
* A.method_defined? :method1 #=> true
* C.method_defined? "method1" #=> true
* C.method_defined? "method2" #=> true
* C.method_defined? "method3" #=> true
* C.method_defined? "method4" #=> false
*/
static VALUE
rb_mod_method_defined(VALUE mod, VALUE mid)
{
return rb_method_boundp(mod, rb_to_id(mid), 1);
}
#define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
/*
* call-seq:
* mod.public_method_defined?(symbol) => true or false
*
* Returns +true+ if the named public method is defined by
* _mod_ (or its included modules and, if _mod_ is a class,
* its ancestors).
*
* module A
* def method1() end
* end
* class B
* protected
* def method2() end
* end
* class C < B
* include A
* def method3() end
* end
*
* A.method_defined? :method1 #=> true
* C.public_method_defined? "method1" #=> true
* C.public_method_defined? "method2" #=> false
* C.method_defined? "method2" #=> true
*/
static VALUE
rb_mod_public_method_defined(VALUE mod, VALUE mid)
{
ID id = rb_to_id(mid);
NODE *method;
method = rb_method_node(mod, id);
if (method) {
if (VISI_CHECK(method->nd_noex, NOEX_PUBLIC))
return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
* mod.private_method_defined?(symbol) => true or false
*
* Returns +true+ if the named private method is defined by
* _ mod_ (or its included modules and, if _mod_ is a class,
* its ancestors).
*
* module A
* def method1() end
* end
* class B
* private
* def method2() end
* end
* class C < B
* include A
* def method3() end
* end
*
* A.method_defined? :method1 #=> true
* C.private_method_defined? "method1" #=> false
* C.private_method_defined? "method2" #=> true
* C.method_defined? "method2" #=> false
*/
static VALUE
rb_mod_private_method_defined(VALUE mod, VALUE mid)
{
ID id = rb_to_id(mid);
NODE *method;
method = rb_method_node(mod, id);
if (method) {
if (VISI_CHECK(method->nd_noex, NOEX_PRIVATE))
return Qtrue;
}
return Qfalse;
}
/*
* call-seq:
* mod.protected_method_defined?(symbol) => true or false
*
* Returns +true+ if the named protected method is defined
* by _mod_ (or its included modules and, if _mod_ is a
* class, its ancestors).
*
* module A
* def method1() end
* end
* class B
* protected
* def method2() end
* end
* class C < B
* include A
* def method3() end
* end
*
* A.method_defined? :method1 #=> true
* C.protected_method_defined? "method1" #=> false
* C.protected_method_defined? "method2" #=> true
* C.method_defined? "method2" #=> true
*/
static VALUE
rb_mod_protected_method_defined(VALUE mod, VALUE mid)
{
ID id = rb_to_id(mid);
NODE *method;
method = rb_method_node(mod, id);
if (method) {
if (VISI_CHECK(method->nd_noex, NOEX_PROTECTED))
return Qtrue;
}
return Qfalse;
}
void
rb_alias(VALUE klass, ID name, ID def)
{
@ -646,9 +808,338 @@ rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
}
static void
secure_visibility(VALUE self)
{
if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) {
rb_raise(rb_eSecurityError,
"Insecure: can't change method visibility");
}
}
static void
set_method_visibility(VALUE self, int argc, VALUE *argv, ID ex)
{
int i;
secure_visibility(self);
for (i = 0; i < argc; i++) {
rb_export_method(self, rb_to_id(argv[i]), ex);
}
rb_clear_cache_by_class(self);
}
/*
* call-seq:
* public => self
* public(symbol, ...) => self
*
* With no arguments, sets the default visibility for subsequently
* defined methods to public. With arguments, sets the named methods to
* have public visibility.
*/
static VALUE
rb_mod_public(int argc, VALUE *argv, VALUE module)
{
secure_visibility(module);
if (argc == 0) {
SCOPE_SET(NOEX_PUBLIC);
}
else {
set_method_visibility(module, argc, argv, NOEX_PUBLIC);
}
return module;
}
/*
* call-seq:
* protected => self
* protected(symbol, ...) => self
*
* With no arguments, sets the default visibility for subsequently
* defined methods to protected. With arguments, sets the named methods
* to have protected visibility.
*/
static VALUE
rb_mod_protected(int argc, VALUE *argv, VALUE module)
{
secure_visibility(module);
if (argc == 0) {
SCOPE_SET(NOEX_PROTECTED);
}
else {
set_method_visibility(module, argc, argv, NOEX_PROTECTED);
}
return module;
}
/*
* call-seq:
* private => self
* private(symbol, ...) => self
*
* With no arguments, sets the default visibility for subsequently
* defined methods to private. With arguments, sets the named methods
* to have private visibility.
*
* module Mod
* def a() end
* def b() end
* private
* def c() end
* private :a
* end
* Mod.private_instance_methods #=> [:a, :c]
*/
static VALUE
rb_mod_private(int argc, VALUE *argv, VALUE module)
{
secure_visibility(module);
if (argc == 0) {
SCOPE_SET(NOEX_PRIVATE);
}
else {
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
}
return module;
}
/*
* call-seq:
* mod.public_class_method(symbol, ...) => mod
*
* Makes a list of existing class methods public.
*/
static VALUE
rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
{
set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
return obj;
}
/*
* call-seq:
* mod.private_class_method(symbol, ...) => mod
*
* Makes existing class methods private. Often used to hide the default
* constructor <code>new</code>.
*
* class SimpleSingleton # Not thread safe
* private_class_method :new
* def SimpleSingleton.create(*args, &block)
* @me = new(*args, &block) if ! @me
* @me
* end
* end
*/
static VALUE
rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
{
set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
return obj;
}
/*
* call-seq:
* public
* public(symbol, ...)
*
* With no arguments, sets the default visibility for subsequently
* defined methods to public. With arguments, sets the named methods to
* have public visibility.
*/
static VALUE
top_public(int argc, VALUE *argv)
{
return rb_mod_public(argc, argv, rb_cObject);
}
static VALUE
top_private(int argc, VALUE *argv)
{
return rb_mod_private(argc, argv, rb_cObject);
}
/*
* call-seq:
* module_function(symbol, ...) => self
*
* Creates module functions for the named methods. These functions may
* be called with the module as a receiver, and also become available
* as instance methods to classes that mix in the module. Module
* functions are copies of the original, and so may be changed
* independently. The instance-method versions are made private. If
* used with no arguments, subsequently defined methods become module
* functions.
*
* module Mod
* def one
* "This is one"
* end
* module_function :one
* end
* class Cls
* include Mod
* def callOne
* one
* end
* end
* Mod.one #=> "This is one"
* c = Cls.new
* c.callOne #=> "This is one"
* module Mod
* def one
* "This is the new one"
* end
* end
* Mod.one #=> "This is one"
* c.callOne #=> "This is the new one"
*/
static VALUE
rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
{
int i;
ID id;
NODE *fbody;
if (TYPE(module) != T_MODULE) {
rb_raise(rb_eTypeError, "module_function must be called for modules");
}
secure_visibility(module);
if (argc == 0) {
SCOPE_SET(NOEX_MODFUNC);
return module;
}
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
for (i = 0; i < argc; i++) {
VALUE m = module;
id = rb_to_id(argv[i]);
for (;;) {
fbody = search_method(m, id, &m);
if (fbody == 0) {
fbody = search_method(rb_cObject, id, &m);
}
if (fbody == 0 || fbody->nd_body == 0) {
rb_bug("undefined method `%s'; can't happen", rb_id2name(id));
}
if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) {
break; /* normal case: need not to follow 'super' link */
}
m = RCLASS_SUPER(m);
if (!m)
break;
}
rb_add_method(rb_singleton_class(module), id, fbody->nd_body->nd_body,
NOEX_PUBLIC);
}
return module;
}
/*
* call-seq:
* obj.respond_to?(symbol, include_private=false) => true or false
*
* Returns +true+> if _obj_ responds to the given
* method. Private methods are included in the search only if the
* optional second parameter evaluates to +true+.
*/
static NODE *basic_respond_to = 0;
int
rb_obj_respond_to(VALUE obj, ID id, int priv)
{
VALUE klass = CLASS_OF(obj);
if (rb_method_node(klass, idRespond_to) == basic_respond_to) {
return rb_method_boundp(klass, id, !priv);
}
else {
VALUE args[2];
int n = 0;
args[n++] = ID2SYM(id);
if (priv)
args[n++] = Qtrue;
return RTEST(rb_funcall2(obj, idRespond_to, n, args));
}
}
int
rb_respond_to(VALUE obj, ID id)
{
return rb_obj_respond_to(obj, id, Qfalse);
}
/*
* call-seq:
* obj.respond_to?(symbol, include_private=false) => true or false
*
* Returns +true+> if _obj_ responds to the given
* method. Private methods are included in the search only if the
* optional second parameter evaluates to +true+.
*/
static VALUE
obj_respond_to(int argc, VALUE *argv, VALUE obj)
{
VALUE mid, priv;
ID id;
rb_scan_args(argc, argv, "11", &mid, &priv);
id = rb_to_id(mid);
if (rb_method_boundp(CLASS_OF(obj), id, !RTEST(priv))) {
return Qtrue;
}
return Qfalse;
}
void
Init_eval_method(void)
{
rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
basic_respond_to = rb_method_node(rb_cObject, idRespond_to);
rb_register_mark_object((VALUE)basic_respond_to);
rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
rb_define_singleton_method(rb_vm_top_self(), "public", top_public, -1);
rb_define_singleton_method(rb_vm_top_self(), "private", top_private, -1);
object_id = rb_intern("object_id");
__send__ = rb_intern("__send__");
eqq = rb_intern("===");
each = rb_intern("each");
aref = rb_intern("[]");
aset = rb_intern("[]=");
match = rb_intern("=~");
missing = rb_intern("method_missing");
added = rb_intern("method_added");
singleton_added = rb_intern("singleton_method_added");
removed = rb_intern("method_removed");
singleton_removed = rb_intern("singleton_method_removed");
undefined = rb_intern("method_undefined");
singleton_undefined = rb_intern("singleton_method_undefined");
}