зеркало из https://github.com/github/ruby.git
* 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:
Родитель
582da7dac7
Коммит
59c061235f
16
ChangeLog
16
ChangeLog
|
@ -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 \
|
||||
|
|
11
compile.c
11
compile.c
|
@ -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
1538
eval.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
34
eval_error.c
34
eval_error.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);
|
||||
|
||||
|
|
158
eval_jump.c
158
eval_jump.c
|
@ -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
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
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
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
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;
|
||||
|
|
10
vm_core.h
10
vm_core.h
|
@ -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");
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче